白黒羊

【C#】Macで読み込めたファイルがWindowsだと読み込めない

エラーメッセージ

JsonReaderException: After parsing a value an unexpected character was encountered: k. Path '[13].value', line 1, position 166727.
Newtonsoft.Json.JsonTextReader.ParsePostValue (System.Boolean ignoreComments) (at <bc3985d37b0241b48fc21474b2de25bd>:0)
Newtonsoft.Json.JsonTextReader.Read () (at <bc3985d37b0241b48fc21474b2de25bd>:0)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ResolvePropertyAndCreatorValues (Newtonsoft.Json.Serialization.JsonObjectContract contract, Newtonsoft.Json.Serialization.JsonProperty containerProperty, Newtonsoft.Json.JsonReader reader, System.Type objectType) (at <bc3985d37b0241b48fc21474b2de25bd>:0)
Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectUsingCreatorWithParameters (Newtonsoft.Json.JsonReader reader, Newtonsoft.Json.Serialization.JsonObjectContract contract, Newtonsoft.Json.Serialization.JsonProperty containerProperty, Newtonsoft.Json.Serialization.ObjectConstructor`1[T] creator, System.String id) (at <bc3985d37b0241b48fc21474b2de25bd>:0)

[......]

Newtonsoft.Json.JsonConvert.DeserializeObject[T] (System.String value, Newtonsoft.Json.JsonSerializerSettings settings) (at <bc3985d37b0241b48fc21474b2de25bd>:0)
Newtonsoft.Json.JsonConvert.DeserializeObject[T] (System.String value) (at <bc3985d37b0241b48fc21474b2de25bd>:0)
Project.Scripts.Domain.Singleton.CachingData.FetchMap (System.Int32 slot) (at Assets/Project/Scripts/Domain/Singleton/CachingData.cs:136)

状況

Unityでマルチプラットフォーム対応のPC向けゲームを作っているのですが、暗号化してUTF-8でファイルに保存しておいたデータを読もうとするとMacでは復号できるのにWindowsではエラーが出てしまいました。
上記エラーメッセージでは Newtonsoftがjsonを読み込めないことが示されていますが、似たような問題で違うメッセージが出ることも考えられます。

using var fs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
var bytes = new byte[fs.Length];
fs.Read(bytes, 0, bytes.Length);
var decrypt = Encryption.Decrypt(bytes, EncryptKey, Iv);
var json = Encoding.UTF8.GetString(decrypt);

MacではUTF-8がデフォルトの文字コードでしたが、私の使っていたWindowsではShift-JISを使っていたことが原因のようでした。保存の際にはUTF-8を指定して保存していたため、文字コードが一致せず、読み込めないという状態になってしまいました。

これを解決するためには明示的に文字コードを指定する必要があります。

解決策

using var fs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using var reader = new BinaryReader(fs, Encoding.UTF8);
var bytes = reader.ReadBytes((int) fs.Length);
var decrypt = Encryption.Decrypt(bytes, EncryptKey, Iv);
var json = Encoding.UTF8.GetString(decrypt);

これで読むときも必ずUTF-8を使うことができます。もちろん書き込むときに他のEncodingを使っているならばそれに合わせたDecodingをしましょう。