[英]Is there any faster alternative to FileStream.WriteByte() method or any way to speed up the FileStream.WriteByte() in C#?
I'm a beginner of C# programming. 我是C#编程的初学者。 Recently I created a simple file encrypting program and a decrypting program.
最近,我创建了一个简单的文件加密程序和一个解密程序。 First I took a file into a FileStream and altered the each byte of the file according to a password.
首先,我将一个文件放入FileStream中,并根据密码更改了文件的每个字节。 Here's what my code
这是我的代码
Code of the Encrypter 加密程式码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Security.Cryptography;
namespace Encrypter
{
class Program
{
static void Main(string[] args)
{
//Actual code starts from here
string file_path = @args[0];
string[] splited_filepath = file_path.Split('\\');
string file_name = splited_filepath[splited_filepath.GetLength(0) - 1];
FileStream file;
if (File.Exists(file_path))
{
file = new FileStream(file_path, FileMode.Open);
if (!file.CanWrite)
{
Console.WriteLine("The file exists, but not writable!");
return;
//goto exit;
}
}
else
{
Console.WriteLine("The file does not exist!\n{0}", file_path);
return;
//goto exit;
}
Console.Write("Enter the password : ");
string password = Console.ReadLine();
if(password == "")
{
Console.WriteLine("Password Cannot be empty!");
return;
}
try
{
while(file.Position < file.Length)
{
int b_input = file.ReadByte();
file.Position--;
file.WriteByte(encrypt_byte(b_input,password,file.Position));
file.Position++;
}
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
return;
//goto exit;
}
file.Close();
string encrypted_file_name = base64_enc(file_name) + compute_hash(password, new MD5CryptoServiceProvider());
string encrypted_file_path = create_encrypted_file_path(encrypted_file_name, splited_filepath);
try
{
File.Move(file_path, encrypted_file_path);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
//exit:;
}
static string create_encrypted_file_path(string enc_filename, string[] splited_fp)
{
string output = "";
for(int a = 0; a < splited_fp.GetLength(0) - 1; a++)
{
output += (splited_fp[a] + "\\");
}
output += enc_filename;
return output;
}
//Encrypting method starts here
static byte encrypt_byte(int input, string pass, long pos)
{
char[] pass_char = pass.ToArray();
int char_pos = Convert.ToInt32(pos % pass_char.GetLength(0));
byte output = Convert.ToByte(
(input + Convert.ToInt32(pass_char[char_pos])) % 256
);
return output;
}
static string compute_hash(string input,HashAlgorithm algorithm)
{
return BitConverter.ToString(algorithm.ComputeHash(Encoding.UTF8.GetBytes(input)));
}
//base64 encoding method
static string base64_enc(string input)
{
return Convert.ToBase64String(Encoding.UTF8.GetBytes(input));
}
}
}
Code of the decrypter 解密器的代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Security.Cryptography;
namespace Decrypter
{
class Program
{
static void Main(string[] args)
{
//Actual code starts from here
string file_path = args[0];
string[] splited_filepath = file_path.Split('\\');
string file_name = splited_filepath[splited_filepath.GetLength(0) - 1];
string encrypted_filename = file_name.Substring(0, file_name.Length - 47);
string hashed_password = file_name.Substring(file_name.Length - 47);
FileStream file;
if (File.Exists(file_path))
{
file = new FileStream(file_path, FileMode.Open);
if (!file.CanWrite)
{
Console.WriteLine("The file exists, but not writable!");
return;
//goto exit;
}
}
else
{
Console.WriteLine("The file does not exist!\n{0}", file_path);
Console.ReadLine();
return;
//goto exit;
}
Console.Write("Enter the password : ");
string password = Console.ReadLine();
if(password == "")
{
Console.WriteLine("Password cannot be empty!");
return;
}
//Varify the password
if(compute_hash(password,new MD5CryptoServiceProvider()) != hashed_password)
{
Console.WriteLine(compute_hash(password, new MD5CryptoServiceProvider()));
Console.WriteLine(hashed_password);
Console.WriteLine("Invalid password!");
return;
}
try
{
while(file.Position < file.Length)
{
int b_input = file.ReadByte();
file.Position--;
file.WriteByte(decrypt_byte(b_input, password, file.Position));
file.Position++;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
return;
//goto exit;
}
file.Close();
string decrypted_filename = base64_dec(encrypted_filename);
string decrypted_filepath = create_decrypted_file_path(decrypted_filename, splited_filepath);
try
{
File.Move(file_path, decrypted_filepath);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
//exit:;
}
//Decrypting method starts here
static byte decrypt_byte(int input, string pass, long pos)
{
char[] pass_char = pass.ToArray();
int char_pos = Convert.ToInt32(pos % pass_char.GetLength(0));
byte output = Convert.ToByte(
get_output_byte(input - Convert.ToInt32(pass_char[char_pos]))
);
return output;
}
//a simple method to get the numaric value of the output byte
static int get_output_byte(int number)
{
if (number < 0) return 256 + number;
else return number;
}
static string compute_hash(string input, HashAlgorithm algorithm)
{
return BitConverter.ToString(algorithm.ComputeHash(Encoding.UTF8.GetBytes(input)));
}
//base64 decoding method
static string base64_dec(string input)
{
return Encoding.UTF8.GetString(Convert.FromBase64String(input));
}
static string create_decrypted_file_path(string enc_filename, string[] splited_fp)
{
string output = "";
for (int a = 0; a < splited_fp.GetLength(0) - 1; a++)
{
output += (splited_fp[a] + "\\");
}
output += enc_filename;
return output;
}
}
}
The problem is both of these programs are considerably slow and it takes hours to encrypt or decrypt large files. 问题在于这两个程序都相当慢,并且需要花费数小时来加密或解密大文件。 Any suggestions to speed up the process?
有什么建议可以加快这个过程吗?
This is about the worst possible way I can think of to use a FileStream
in a loop: 这大约是最坏的方式,我能想到的使用
FileStream
在一个循环:
int b_input = file.ReadByte();
file.Position--;
file.WriteByte(encrypt_byte(b_input,password,file.Position));
file.Position++;
Okay, the first line isn't bad. 好吧,第一行还不错。 The second line causes the stream to flush its write buffer and invalidate its read buffer.
第二行使流刷新其写缓冲区并使它的读缓冲区无效。 Then we write a new byte and adjust the position again, causing another flush and invalidation (and causes us to skip every other byte to boot, because the
WriteByte
already updated the file position). 然后,我们写入一个新字节并再次调整位置,从而导致另一个刷新和无效操作(并导致我们跳过其他所有字节来启动,因为
WriteByte
已更新文件位置)。
Simple solution is to use File.ReadAllBytes
and just operate in memory. 一个简单的解决方案是使用
File.ReadAllBytes
并仅在内存中进行操作。 However, as you yourself observed, this doesn't work well for large files. 但是,正如您自己观察到的那样,这不适用于大文件。
Instead, you should work with a reasonably sized buffer (say var buffer = new byte[4096];
) and then use file.Read
to read the file in chunks 1 . 相反,您应该使用大小适当的缓冲区(例如
var buffer = new byte[4096];
),然后使用file.Read
读取块1中的文件。 It's better if you can also use a separate stream pointing at a second file for the write side so that you still benefit from buffers on both sides. 最好还可以使用指向第二个文件的单独流作为写入侧,以便仍可以从两侧的缓冲区中受益。
You have to maintain your own count of the position within the file rather than relying on the file's Position
property, and your loop should terminate when Read
returns 0
(but make sure you're always paying attention to that value and only process that much of the buffer). 您必须维护自己在文件中位置的数量,而不是依靠文件的
Position
属性,并且循环应在Read
返回0
时终止(但请确保您始终注意该值并且仅处理该值的大部分)缓冲区)。
Finally, close both streams, delete the old file and move/rename the new file to replace it. 最后,关闭两个流,删除旧文件并移动/重命名新文件以替换它。
Note that this sort of "encryption" is suitable for toy usage but shouldn't be seriously used for anything. 请注意,这种“加密”适用于玩具使用,但不应认真用于任何东西。 You're already aware of the
System.Security.Cryptography
namespace. 您已经知道
System.Security.Cryptography
命名空间。 For any serious encryption work, you should be looking for existing classes in there, not rolling your own. 对于任何认真的加密工作,您应该在其中寻找现有的类,而不要自己滚动。
1 Consider also using Async
variants. 1考虑也使用
Async
变量。 Most of the time will still be spent doing I/O . 大部分时间仍然会花在I / O上 。 Blocking a thread whilst that's happening doesn't add much value to the system.
在这种情况下阻塞线程不会为系统增加太多价值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.