【发布时间】:2015-09-03 21:50:20
【问题描述】:
我正在用 C# 开发一个游戏,其中每个“地区”都会定期将有关它的数据存储在保存文件中。为了测试,“SaveAll”方法在关卡开始时被调用一次。
文件操作代码如下:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.IO;
public class DistrictSaveData : KeepAwake {
private string saveDirectoryPath = string.Concat(
System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments),
"\\My Games\\District\\Districts");
private string saveFilePath = string.Concat(
System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments),
"\\My Games\\District\\Districts\\District-x.dat");
private StreamReader saveFileReader;
public void SaveAll() {
foreach (GameObject gO in GameObject.FindGameObjectsWithTag("District")) {
District district = gO.GetComponent<District>();
saveFilePath = string.Concat(
System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments),
"\\My Games\\District\\Districts\\District-", district.id , ".dat");
if (!Directory.Exists(saveDirectoryPath)) {
Directory.CreateDirectory(saveDirectoryPath);
}
try {
File.Delete(saveFilePath);
} catch {}
File.Create(saveFilePath);
File.WriteAllText(saveFilePath, district.SendSaveData());
}
}
public void LoadAll() {
foreach (GameObject gO in GameObject.FindGameObjectsWithTag("District")) {
District district = gO.GetComponent<District>();
saveFilePath = string.Concat(
System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments),
"\\My Games\\District\\Districts\\District-", district.id , ".dat");
if(File.Exists(saveFilePath)) {
OpenFileForReading();
district.isHQ = bool.Parse(saveFileReader.ReadLine());
district.controllingFaction = StringToFaction(saveFileReader.ReadLine());
district.agricultureSpecialisation = StringToAgricultureSpecialisation(saveFileReader.ReadLine());
district.technologySpecialisation = StringToTechnologySpecialisation(saveFileReader.ReadLine());
district.militarySpecialisation = StringToMilitarySpecialisation(saveFileReader.ReadLine());
CloseFileAfterReading();
} else
break;
}
}
/// <summary>
/// Opens the save file for reading.
/// </summary>
private void OpenFileForReading() {
saveFileReader = File.OpenText(saveFilePath);
}
/// <summary>
/// Closes the save file after reading.
/// </summary>
private void CloseFileAfterReading() {
saveFileReader.Close();
}
private Faction StringToFaction(string stringToConvert) {
switch (stringToConvert) {
case "TheCrimsonLegion":
return Faction.TheCrimsonLegion;
case "TheVanguardsOfChaos":
return Faction.TheVanguardsOfChaos;
case "TheEmeraldFoxes":
return Faction.TheEmeraldFoxes;
case "TheSyndicate":
return Faction.TheSyndicate;
case "TheKeepersOfTheTome":
return Faction.TheKeepersOfTheTome;
case "TheArchitectsOfThought":
return Faction.TheArchitectsOfThought;
default:
return Faction.None;
}
}
private AgricultureSpecialisation StringToAgricultureSpecialisation(string stringToConvert) {
switch (stringToConvert) {
case "Farm":
return AgricultureSpecialisation.Farm;
case "Plantation":
return AgricultureSpecialisation.Plantation;
case "Biodome":
return AgricultureSpecialisation.Biodome;
default:
return AgricultureSpecialisation.None;
}
}
private TechnologySpecialisation StringToTechnologySpecialisation(string stringToConvert) {
switch (stringToConvert) {
case "Laboratory":
return TechnologySpecialisation.Laboratory;
case "University":
return TechnologySpecialisation.University;
case "GreatTechnologicalInstitution":
return TechnologySpecialisation.GreatTechnologicalInstitution;
default:
return TechnologySpecialisation.None;
}
}
private MilitarySpecialisation StringToMilitarySpecialisation(string stringToConvert) {
switch (stringToConvert) {
case "Outpost":
return MilitarySpecialisation.Outpost;
case "Barracks":
return MilitarySpecialisation.Barracks;
case "Fortress":
return MilitarySpecialisation.Fortress;
default:
return MilitarySpecialisation.None;
}
}
}
抛出的异常(多次)如下:
IOException: Sharing violation on path C:\users\samdy1\My Documents\My Games\District\Districts\District-0.dat
System.IO.FileStream..ctor (System.String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, Boolean anonymous, FileOptions options) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.IO/FileStream.cs:320)
System.IO.FileStream..ctor (System.String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize)
(wrapper remoting-invoke-with-check) System.IO.FileStream:.ctor (string,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare,int)
System.IO.File.Create (System.String path, Int32 bufferSize) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.IO/File.cs:135)
System.IO.File.Create (System.String path) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.IO/File.cs:130)
DistrictSaveData+<SaveAll>c__Iterator3.MoveNext () (at Assets/Scripts/_Core/SaveData/DistrictSaveData.cs:29)
在 SaveAll 方法中进程的第 28 行和第 29 行抛出此异常。但是,SaveAll 方法不使用流,所以我看不到如何保持打开状态。事实上,此时关卡中,读取流根本没有打开。
我是否遗漏了一些明显的东西?
【问题讨论】:
-
旁注:考虑
Path.Combine而不是string.Concat。它会自动确保正确处理路径分隔符。 -
那些文件系统阅读器等是
IDisposable。我认为与其将实例作为成员,不如应用using reader = new FileReader(path) { ... }方法。 -
原因是,如果在读取文件时抛出异常,您不会关闭它们。
-
第二个原因是,如果您碰巧有多个线程处理不同的文件,那么您需要担心的事情也会更少。
-
@EricJ。此时尚未调用 LoadAll() 中的代码,因此读取它们不会引发异常。无论如何,我尝试在导致问题的 File.Create() 和 File.WriteAllText() 行之前关闭文件,但仍然出现相同的错误。
标签: c# io system.io.file sharing-violation