问题
I am encrypting some text files. It works fine the file is encypted, however on occasion I get this error when attempting to delete the original unencrypted file:
System.IO.IOException: The process cannot access the file 'MyFile.TXT' because it is being used by another process. at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.File.Delete(String path) at FileEncryption.Program.DeleteFile(String sInputFilename) in FileEncryption\Program.cs:line 159
This seems to happen on large text files. (50MB+) but not always.
Any idea what I might be doing wrong?
Method to PROCESS the folder of txt files:
private static void BeginFileProcessing(string sSecretKey_)
{
DirectoryInfo di = new DirectoryInfo(_sourcePath);
FileInfo[] files = di.GetFiles(_fileType);
try
{
foreach (FileInfo file in files)
{
string thisFileExt = Path.GetExtension(file.Name);
string thisFileName = Path.GetFileNameWithoutExtension(file.Name);
string encFileName = String.Format("{0}-enc{1}", thisFileName, thisFileExt);
if (_TestingOnly)
{
Console.Write("Source: " + file.Name + " " +
" Encrypted File: " + encFileName + "\n");
}
EncryptFile(file.FullName, _targetPath + encFileName, sSecretKey_);
if (_DeleteOriginal)
{
Console.WriteLine("Deleteing file: " + file.FullName);
DeleteFile(file.FullName);
}
}
}
catch (Exception ex)
{
LogWriter(string.Format("\nError Decrypting file: {0}", ex), true);
}
}
Method to ENCRYPT the files
private static void EncryptFile(string sInputFilename,
string sOutputFilename, string sKey)
{
FileStream fsInput =
new FileStream(sInputFilename, FileMode.Open, FileAccess.Read);
FileStream fsEncrypted =
new FileStream(sOutputFilename, FileMode.Create, FileAccess.Write);
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
ICryptoTransform desencrypt = DES.CreateEncryptor();
CryptoStream cryptostream =
new CryptoStream(fsEncrypted, desencrypt, CryptoStreamMode.Write);
try
{
byte[] bytearrayinput = System.IO.File.ReadAllBytes(sInputFilename);
fsInput.Read(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Close();
fsInput.Close();
fsEncrypted.Close();
}
catch (Exception ex)
{
string error = "";
foreach (DictionaryEntry pair in ex.Data)
{
error += pair.Key + " = " + pair.Value + "\n";
Console.WriteLine(error);
}
LogWriter(error, true);
}
}
Method to DELETE the files
private static void DeleteFile(string sInputFilename)
{
try
{
if (_TestingOnly)
{
Console.WriteLine("TESTING ONLY! File: " + sInputFilename + " would have been deleted.");
}
else
{
File.Delete(sInputFilename);
}
}
catch (Exception ex)
{
Console.Write(ex.ToString());
LogWriter(ex.ToString(), true);
}
}
回答1:
This may be caused by your files not being closed after the call to EncryptFile
. In your original code, if you hit an exception in EncryptFile
the streams would be left open if the exception happens before the call to Close
. Using Using
statements makes this easier but you can also put the Close
in a finally
block and close the streams if they're not null.
Here's an example using Using
:
private static void EncryptFile(string sInputFilename,
string sOutputFilename, string sKey)
{
using(FileStream fsInput = new FileStream(sInputFilename, FileMode.Open, FileAccess.Read),
FileStream fsEncrypted = new FileStream(sOutputFilename, FileMode.Create, FileAccess.Write))
{
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
ICryptoTransform desencrypt = DES.CreateEncryptor();
using(CryptoStream cryptostream =
new CryptoStream(fsEncrypted, desencrypt, CryptoStreamMode.Write))
{
try
{
byte[] bytearrayinput = System.IO.File.ReadAllBytes(sInputFilename);
fsInput.Read(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length);
}
catch (Exception ex)
{
string error = "";
foreach (DictionaryEntry pair in ex.Data)
{
error += pair.Key + " = " + pair.Value + "\n";
Console.WriteLine(error);
}
LogWriter(error, true);
}
}
}
}
Edit
My proposed code will solve the issue of the file stream being left open. However, the root of the issue is that the system throws an OutOfMemoryException
while reading the file if it's large. The original code would read all the bytes then read the bytes again into the same buffer, which is a waste of memory and a waste of time. Below is a corrected version:
private static void EncryptFile(string sInputFilename,
string sOutputFilename, string sKey)
{
using(FileStream fsInput = new FileStream(sInputFilename, FileMode.Open, FileAccess.Read),
fsEncrypted = new FileStream(sOutputFilename, FileMode.Create, FileAccess.Write))
{
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
ICryptoTransform desencrypt = DES.CreateEncryptor();
using(CryptoStream cryptostream =
new CryptoStream(fsEncrypted, desencrypt, CryptoStreamMode.Write))
{
byte[] buffer = new byte[2048];
int readCount = 0;
try
{
while ((readCount = fsInput.Read(buffer, 0, 2048)) > 0)
{
cryptostream.Write(buffer, 0, readCount);
}
}
catch (Exception ex)
{
string error = "";
foreach (DictionaryEntry pair in ex.Data)
{
error += pair.Key + " = " + pair.Value + "\n";
Console.WriteLine(error);
}
LogWriter(error, true);
}
}
}
}
回答2:
You should consider using using
statements for all objects that implement IDisposable
. This will ensure that they are closed and disposed at the end of the using
block:
private static void EncryptFile(string sInputFilename, string sOutputFilename,
string sKey)
{
using (var fsInput = new FileStream(sInputFilename, FileMode.Open,
FileAccess.Read))
using (var fsEncrypted = new FileStream(sOutputFilename, FileMode.Create,
FileAccess.Write))
using (var desCryptoProvider = new DESCryptoServiceProvider())
{
desCryptoProvider.Key = Encoding.ASCII.GetBytes(sKey);
desCryptoProvider.IV = Encoding.ASCII.GetBytes(sKey);
using (var encryptor = desCryptoProvider.CreateEncryptor())
using (var cryptoStream = new CryptoStream(fsEncrypted, encryptor,
CryptoStreamMode.Write))
{
try
{
var bytearrayinput = File.ReadAllBytes(sInputFilename);
fsInput.Read(bytearrayinput, 0, bytearrayinput.Length);
cryptoStream.Write(bytearrayinput, 0, bytearrayinput.Length);
}
catch (Exception ex)
{
var errors = new StringBuilder();
foreach (var pair in ex.Data)
{
errors.AppendLine(string.Format("{0} = {1}", pair.Key, pair.Value));
}
Console.WriteLine(errors.ToString());
LogWriter(errors.ToString(), true);
}
}
}
}
回答3:
It's not exactly an answer, but may help; a simple method to check if a file is locked:
bool IsFileAvailable(string fileName)
{
FileStream stream = null;
try
{
FileInfo fileInfo = new FileInfo(fileName);
stream = fileInfo.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch (IOException)
{
// File is not present, or locked by another process
return false;
}
finally
{
if (stream != null)
stream.Close();
}
// File is present and not locked
return true;
}
来源:https://stackoverflow.com/questions/29171568/unable-to-delete-some-files-via-system-io-file-in-c-sharp-console-app