读取大文件,文件大小错误

use*_*462 0 c# file

我正在尝试从磁盘读取大文件并在加载时报告百分比.问题是FileInfo.Length报告的大小不同于我的Encoding.ASCII.GetBytes().长度.

    public void loadList()
    {
        string ListPath = InnerConfig.dataDirectory + core.operation[operationID].Operation.Trim() + "/List.txt";
        FileInfo f = new FileInfo(ListPath);

        int bytesLoaded = 0;

        using (FileStream fs = File.Open(ListPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
        using (BufferedStream bs = new BufferedStream(fs))
        using (StreamReader sr = new StreamReader(bs))
        {
            string line;
            while ((line = sr.ReadLine()) != null)
            {
                byte[] array = Encoding.ASCII.GetBytes(line);
                bytesLoaded += array.Length;
            }
        }

        MessageBox.Show(bytesLoaded + "/" + f.Length);
    }
Run Code Online (Sandbox Code Playgroud)

结果是

    13357/15251
Run Code Online (Sandbox Code Playgroud)

有1900个字节'缺失'.该文件包含短字符串列表.有什么提示为什么它报告不同的文件大小?是否必须对文件中的'\ r'和'\n'字符执行任何操作?另外,我有以下几行:

    int bytesLoaded = 0;
Run Code Online (Sandbox Code Playgroud)

如果文件是1GB大,我是否必须使用'long'代替?感谢您的时间!

Dou*_*las 5

你的直觉是正确的; 报告大小的差异是由于换行符所致.根据MSDN文档StreamReader.ReadLine:

返回的字符串不包含终止回车符或换行符.

根据创建文件的来源,每个换行符包含一个或两个字符(最常见的是:\r\n在Windows上;仅\n在Linux上).

也就是说,如果您打算将文件作为字节序列读取(不考虑行),则应使用该FileStream.Read方法,这样可以避免ASCII编码的开销(以及返回正确的计数total):

byte[] array = new byte[1024];   // buffer
int total = 0;
using (FileStream fs = File.Open(ListPath, FileMode.Open, 
                                 FileAccess.Read, FileShare.ReadWrite))
{
    int read;
    while ((read = fs.Read(array, 0, array.Length)) > 0)
    {
        total += read;
        // process "array" here, up to index "read"
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:spender提出了关于字符编码的重要观点; 您的代码应仅用于ASCII文本文件.如果您的文件是使用不同的编码编写的 - 今天最流行的是UTF-8 - 那么结果可能不正确.

例如,考虑三字节十六进制序列E2-98-BA.默认StreamReader使用UTF8Encoding,将其解码为单个字符?.但是,此字符不能用ASCII表示; 因此,调用Encoding.ASCII.GetBytes("?")将返回与回退字符的ASCII值相对应的单个字节?,从而导致字符数丢失(以及字节数组的错误处理).

最后,还有可能在文本文件的开头有一个编码前同步码(例如Unicode字节顺序标记),它也会被它剥离ReadLine,导致几个字节的进一步差异.