流无法关闭 C#
Stream failing to close C#
我正在创建一个程序,该程序获取密码并将其编码应用到一个文件上,我创造性地 将其标记为 PASSWORDFILE 文件。我是一名自学成才的业余程序员,这是我第一次使用流 => 抱歉,我的代码不够简洁。当我为我的文件添加密码时,文件拒绝打开(给我 "System.IO.IOException: The process cannot access the file '[file path here]' because it is being used by another process.")。我已确保关闭所有流,但此错误仍然存在。
进一步混淆:
namespace PasswordSaver
{
[Serializable]
class Password
{
public string ID;
string baseWord;
public Password(string password, string ID)
{
this.ID = ID;
baseWord = password;
}
public virtual string GetPassword()
{
return baseWord;
}
}
[Serializable]
class EncodedPassword : Password
{
EncoderAndDecoder Encoder;
public EncodedPassword(string decodedBasePassword, string ID) : base(decodedBasePassword, ID)
{
Encoder = new EncoderAndDecoder();
}
public override string GetPassword()
{
return Encoder.Encode(base.GetPassword(), out _);
}
}
[Serializable]
class EncodedPasswordWithAddendum : EncodedPassword
{
string addendum;
public EncodedPasswordWithAddendum(string decodedBasePassword, string addendum, string ID) : base(decodedBasePassword, ID)
{
this.addendum = addendum;
}
public override string GetPassword()
{
return base.GetPassword() + addendum;
}
}
}
仅当我尝试添加 EncodedPassword
或 EncodedPasswordWithAddendum
实例而不是 Password
实例时才会发生错误。
我写的代码是
namespace PasswordSaver
{
class PasswordWriter
{
public readonly string saveFilePath;
static string directory = Directory.GetCurrentDirectory();
#region Constructors
public PasswordWriter()
{
saveFilePath = directory + @"\PasswordSaver"
+ ".passwordfile";
}
public PasswordWriter(string saveFilePath)
{
this.saveFilePath = saveFilePath;
}
#endregion
#region Individual Writing Functions
private void WriteBinary(object objectToEncode)
{
WriteBinary(objectToEncode, out _);
}
private void WriteBinary(object objectToEncode, out Exception exception)
{
exception = null;
try
{
IFormatter binaryFormatter = new BinaryFormatter();
Stream fileStream = new FileStream(saveFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
Stream memoryStream = new MemoryStream();
memoryStream.Position = memoryStream.Length;
binaryFormatter.Serialize(memoryStream, objectToEncode);
EncodeFromStream(ref memoryStream, ref fileStream);
fileStream.Close();
memoryStream.Close();
}
catch (Exception e)
{
exception = e;
}
}
#endregion
#region File Read and Writing
public void WriteFile(Password[] passwords)
{
if (File.Exists(saveFilePath))
{
Stream stream = new FileStream(saveFilePath, FileMode.Truncate, FileAccess.Write);
stream.Close();
}
WriteBinary(passwords.Length);
foreach (Password password in passwords)
{
WriteBinary(password);
}
}
public void WriteToFile(Password password)
{
Password[] oldPasswords = ReadFile();
Password[] passwords = new Password[oldPasswords.Length + 1];
for (int i = 0; i < oldPasswords.Length; i++)
{
passwords[i] = oldPasswords[i];
}
passwords[oldPasswords.Length] = password;
WriteFile(passwords);
}
public bool ReplacePassword(string oldPasswordID, Password newPassword)
{
Password[] passwords = ReadFile();
for (int i = 0; i < passwords.Length; i++)
{
if (passwords[i].ID == oldPasswordID)
{
passwords[i] = newPassword;
return true;
}
}
return false;
}
public Password[] ReadFile()
{
Stream fileStream = new FileStream(saveFilePath, FileMode.OpenOrCreate, FileAccess.Read);
IFormatter binaryFormatter = new BinaryFormatter();
Stream memoryStream = new MemoryStream();
DecodeFromStream(ref fileStream, ref memoryStream);
fileStream.Close();
memoryStream.Position = 0;
int length = (int) binaryFormatter.Deserialize(memoryStream);
//Console.WriteLine(length + " is the length");//debug
Password[] passwords = new Password[length];
for (int i = 0; i < length; i++)
{
//Console.WriteLine(memoryStream.Position + " " + memoryStream.Length);//debug
//Console.WriteLine(i);//debug
passwords[i] = (Password)binaryFormatter.Deserialize(memoryStream);
}
memoryStream.Close();
return passwords;
}
#endregion
#region Encode and Decode
private void EncodeFromStream(ref Stream stream, ref Stream newStream)
{
stream.Position = 0;
newStream.Position = newStream.Length;
for (int i = 0; i < stream.Length; i++)
{
int integer = stream.ReadByte();
byte originalByte = (byte)integer;// get a byte off of the line
//Encode byte here
newStream.WriteByte(setOfBits1);
newStream.WriteByte(setOfBits2);
}
}
private void DecodeFromStream(ref Stream stream, ref Stream newStream)
{
newStream.Position = newStream.Length;
stream.Position = 0;
for (int i = 0; i < (stream.Length / 2); i++)// stream.Length / 2 because the program reads two bytes per iteration of the for loop
{
//I decode the bytes here
newStream.WriteByte(originalByte);
}
}
#endregion
public void WriteContentsToFile()
{
Stream stream = new FileStream(saveFilePath + "1", FileMode.OpenOrCreate, FileAccess.ReadWrite);
Stream stream1 = new FileStream(saveFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
this.DecodeFromStream(ref stream1, ref stream);
stream.Close();
stream1.Close();
}
}
}
我删除了对 EncodeFromStream
和 DecodeFromStream
中的流进行编码和解码的代码。
new FileStream(saveFilePath + "1", FileMode.OpenOrCreate, FileAccess.ReadWrite)
的任何出现都是我以解码格式写入单独文件的地方。为了区分这两个文件,我将文件类型从 PASSWORDFILE 更改为 PASSWORDFILE1.
总结:
我将 WriteFile
或 WriteToFile
方法与包含 EncodedPassword
或 EncodedPasswordWithAddendum
的 Password[]
一起使用。然后,当我尝试通过 FileStream
(通常通过方法 ReadFile
)打开文件时,我得到了异常 "System.IO.IOException: The process cannot access the file '[file path here]' because it is being used by another process"。
感谢您的帮助。
流通常包含未管理的资源(OS 文件句柄),因此它们实现了 IDisposeable。
虽然您始终可以确定 GC 会最终 清理一次性物品(最迟在应用程序关闭时),但通常这是迟到的方式。你必须明确地去做。为此,我有一个关于 IDisposeable 东西的规则:
"Never split up the creation and disposing of a disposeable resource. Create. Use. Dispose. All in the same piece of code, ideally using a using block."
我遇到的唯一例外是日志文件。没有什么比 远程 值得麻烦和头疼的是保持一次性打开的东西了。尤其是性能。
由于 using block 使用了一个尝试......最后,你可以确定它会 运行。编译器和 运行time 确保某些 finally 块始终 运行,即使在函数 return 上,通过 goto 或异常情况跳转。
我正在创建一个程序,该程序获取密码并将其编码应用到一个文件上,我创造性地 将其标记为 PASSWORDFILE 文件。我是一名自学成才的业余程序员,这是我第一次使用流 => 抱歉,我的代码不够简洁。当我为我的文件添加密码时,文件拒绝打开(给我 "System.IO.IOException: The process cannot access the file '[file path here]' because it is being used by another process.")。我已确保关闭所有流,但此错误仍然存在。
进一步混淆:
namespace PasswordSaver
{
[Serializable]
class Password
{
public string ID;
string baseWord;
public Password(string password, string ID)
{
this.ID = ID;
baseWord = password;
}
public virtual string GetPassword()
{
return baseWord;
}
}
[Serializable]
class EncodedPassword : Password
{
EncoderAndDecoder Encoder;
public EncodedPassword(string decodedBasePassword, string ID) : base(decodedBasePassword, ID)
{
Encoder = new EncoderAndDecoder();
}
public override string GetPassword()
{
return Encoder.Encode(base.GetPassword(), out _);
}
}
[Serializable]
class EncodedPasswordWithAddendum : EncodedPassword
{
string addendum;
public EncodedPasswordWithAddendum(string decodedBasePassword, string addendum, string ID) : base(decodedBasePassword, ID)
{
this.addendum = addendum;
}
public override string GetPassword()
{
return base.GetPassword() + addendum;
}
}
}
仅当我尝试添加 EncodedPassword
或 EncodedPasswordWithAddendum
实例而不是 Password
实例时才会发生错误。
我写的代码是
namespace PasswordSaver
{
class PasswordWriter
{
public readonly string saveFilePath;
static string directory = Directory.GetCurrentDirectory();
#region Constructors
public PasswordWriter()
{
saveFilePath = directory + @"\PasswordSaver"
+ ".passwordfile";
}
public PasswordWriter(string saveFilePath)
{
this.saveFilePath = saveFilePath;
}
#endregion
#region Individual Writing Functions
private void WriteBinary(object objectToEncode)
{
WriteBinary(objectToEncode, out _);
}
private void WriteBinary(object objectToEncode, out Exception exception)
{
exception = null;
try
{
IFormatter binaryFormatter = new BinaryFormatter();
Stream fileStream = new FileStream(saveFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
Stream memoryStream = new MemoryStream();
memoryStream.Position = memoryStream.Length;
binaryFormatter.Serialize(memoryStream, objectToEncode);
EncodeFromStream(ref memoryStream, ref fileStream);
fileStream.Close();
memoryStream.Close();
}
catch (Exception e)
{
exception = e;
}
}
#endregion
#region File Read and Writing
public void WriteFile(Password[] passwords)
{
if (File.Exists(saveFilePath))
{
Stream stream = new FileStream(saveFilePath, FileMode.Truncate, FileAccess.Write);
stream.Close();
}
WriteBinary(passwords.Length);
foreach (Password password in passwords)
{
WriteBinary(password);
}
}
public void WriteToFile(Password password)
{
Password[] oldPasswords = ReadFile();
Password[] passwords = new Password[oldPasswords.Length + 1];
for (int i = 0; i < oldPasswords.Length; i++)
{
passwords[i] = oldPasswords[i];
}
passwords[oldPasswords.Length] = password;
WriteFile(passwords);
}
public bool ReplacePassword(string oldPasswordID, Password newPassword)
{
Password[] passwords = ReadFile();
for (int i = 0; i < passwords.Length; i++)
{
if (passwords[i].ID == oldPasswordID)
{
passwords[i] = newPassword;
return true;
}
}
return false;
}
public Password[] ReadFile()
{
Stream fileStream = new FileStream(saveFilePath, FileMode.OpenOrCreate, FileAccess.Read);
IFormatter binaryFormatter = new BinaryFormatter();
Stream memoryStream = new MemoryStream();
DecodeFromStream(ref fileStream, ref memoryStream);
fileStream.Close();
memoryStream.Position = 0;
int length = (int) binaryFormatter.Deserialize(memoryStream);
//Console.WriteLine(length + " is the length");//debug
Password[] passwords = new Password[length];
for (int i = 0; i < length; i++)
{
//Console.WriteLine(memoryStream.Position + " " + memoryStream.Length);//debug
//Console.WriteLine(i);//debug
passwords[i] = (Password)binaryFormatter.Deserialize(memoryStream);
}
memoryStream.Close();
return passwords;
}
#endregion
#region Encode and Decode
private void EncodeFromStream(ref Stream stream, ref Stream newStream)
{
stream.Position = 0;
newStream.Position = newStream.Length;
for (int i = 0; i < stream.Length; i++)
{
int integer = stream.ReadByte();
byte originalByte = (byte)integer;// get a byte off of the line
//Encode byte here
newStream.WriteByte(setOfBits1);
newStream.WriteByte(setOfBits2);
}
}
private void DecodeFromStream(ref Stream stream, ref Stream newStream)
{
newStream.Position = newStream.Length;
stream.Position = 0;
for (int i = 0; i < (stream.Length / 2); i++)// stream.Length / 2 because the program reads two bytes per iteration of the for loop
{
//I decode the bytes here
newStream.WriteByte(originalByte);
}
}
#endregion
public void WriteContentsToFile()
{
Stream stream = new FileStream(saveFilePath + "1", FileMode.OpenOrCreate, FileAccess.ReadWrite);
Stream stream1 = new FileStream(saveFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
this.DecodeFromStream(ref stream1, ref stream);
stream.Close();
stream1.Close();
}
}
}
我删除了对 EncodeFromStream
和 DecodeFromStream
中的流进行编码和解码的代码。
new FileStream(saveFilePath + "1", FileMode.OpenOrCreate, FileAccess.ReadWrite)
的任何出现都是我以解码格式写入单独文件的地方。为了区分这两个文件,我将文件类型从 PASSWORDFILE 更改为 PASSWORDFILE1.
总结:
我将 WriteFile
或 WriteToFile
方法与包含 EncodedPassword
或 EncodedPasswordWithAddendum
的 Password[]
一起使用。然后,当我尝试通过 FileStream
(通常通过方法 ReadFile
)打开文件时,我得到了异常 "System.IO.IOException: The process cannot access the file '[file path here]' because it is being used by another process"。
感谢您的帮助。
流通常包含未管理的资源(OS 文件句柄),因此它们实现了 IDisposeable。
虽然您始终可以确定 GC 会最终 清理一次性物品(最迟在应用程序关闭时),但通常这是迟到的方式。你必须明确地去做。为此,我有一个关于 IDisposeable 东西的规则:
"Never split up the creation and disposing of a disposeable resource. Create. Use. Dispose. All in the same piece of code, ideally using a using block." 我遇到的唯一例外是日志文件。没有什么比 远程 值得麻烦和头疼的是保持一次性打开的东西了。尤其是性能。
由于 using block 使用了一个尝试......最后,你可以确定它会 运行。编译器和 运行time 确保某些 finally 块始终 运行,即使在函数 return 上,通过 goto 或异常情况跳转。