diff --git a/src/Yi/Rope.hs b/src/Yi/Rope.hs
--- a/src/Yi/Rope.hs
+++ b/src/Yi/Rope.hs
@@ -1,6 +1,7 @@
 {-# LANGUAGE BangPatterns #-}
 {-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE OverloadedStrings #-}
 {-# OPTIONS_HADDOCK show-extensions #-}
 
 -- |
@@ -75,6 +76,7 @@
 import           Data.Monoid
 import           Data.String (IsString(..))
 import qualified Data.Text as TX
+import qualified Data.Text.Encoding as TXE
 import           Data.Text.ICU.Convert
 import qualified Data.Text.IO as TF (writeFile)
 import           Data.Typeable
@@ -669,15 +671,27 @@
 -- brand new file, you can use 'writeFileUsingText'.
 --
 -- It's up to the user to handle exceptions.
-writeFile :: FilePath -> YiString -> ConverterName -> IO ()
+--
+-- Returns an error message if conversion failed, otherwise Nothing
+-- on success.
+writeFile :: FilePath -> YiString -> ConverterName -> IO (Maybe TX.Text)
 writeFile f s (CN cn) = open cn (Just True) >>= writeFileWithConverter f s
 
 -- | As 'writeFile' but using the provided 'Converter' rather than
 -- creating one from a 'ConverterName'.
 --
 -- It's up to the user to handle exceptions.
-writeFileWithConverter :: FilePath -> YiString -> Converter -> IO ()
-writeFileWithConverter f s c = BS.writeFile f (fromUnicode c $ toText s)
+writeFileWithConverter :: FilePath -> YiString -> Converter -> IO (Maybe TX.Text)
+writeFileWithConverter f s c = do
+    let bytes = fromUnicode c $ toText s
+        errorMsg = "Could not encode text with specified encoding"
+    enc <- detectEncoding errorMsg $ BSL.fromChunks [bytes]
+    case enc of
+        Left err -> return $ Just err
+        Right (_, (CN cn)) -> do
+            if cn == getName c
+                then BS.writeFile f bytes >> return Nothing
+                else return . Just $ errorMsg
 
 -- | Write a 'YiString' into the given file. This function uses
 -- 'TF.writeFile' to do the writing: if you have special needs for
@@ -698,15 +712,29 @@
 -- It is up to the user to handle exceptions not directly related to
 -- character decoding.
 readFile :: FilePath -> IO (Either TX.Text (YiString, ConverterName))
-readFile fp = do
-  cs <- BSL.readFile fp
+readFile fp = BSL.readFile fp >>= detectEncoding err
+    where err = "Could not guess the encoding of " <> TX.pack fp
+
+-- | Detects the encoding of a sequence of bytes.
+--
+-- Presumably the calculating the 'YiString' is lazy so it is fine
+-- to use this to only get the converter name.
+--
+-- Also allows specification of the error to return if the encoding
+-- of the bytes cannot be detected. The error returns won't necessarily
+-- be this error - it is used only if no encoding name is detected at all.
+detectEncoding :: TX.Text -> BSL.ByteString
+               -> IO (Either TX.Text (YiString, ConverterName))
+detectEncoding err cs =
   case detectEncodingName cs of
-   Nothing -> return . Left . TX.pack $ "Could not guess the encoding of " <> fp
+   Nothing -> return $ case TXE.decodeUtf8' $ BSL.toStrict cs of
+      -- The detection failed but stay optimistic and try as UTF8 anyway.
+     Left _ -> Left err
+     Right tx -> Right (fromText tx, CN "UTF-8")
    Just enc -> do
      let ke = if enc == "ASCII" then Just "UTF-8" else listToMaybe $ aliases enc
      case ke of
-      Nothing -> return . Left . TX.pack $
-                   "Don't know how to decode as " <> enc
+      Nothing -> return . Left . TX.pack $ "Don't know how to decode as " <> enc
       Just s -> do
         c <- open s (Just True)
         let st = BSL.toStrict cs
diff --git a/yi-rope.cabal b/yi-rope.cabal
--- a/yi-rope.cabal
+++ b/yi-rope.cabal
@@ -1,5 +1,5 @@
 name:                yi-rope
-version:             0.6.0.0
+version:             0.7.0.0
 synopsis:            A rope data structure used by Yi
 description:         A rope data structure used by Yi
 license:             GPL-2
