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

本文关键字:文件大小 错误 文件 读取 | 更新日期: 2023-09-27 18:17:32

我正在尝试从磁盘读取一个大文件并在加载时报告百分比。问题是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);
    }

结果是

    13357/15251

有 1900 字节"丢失"。该文件包含短字符串的列表。为什么它报告不同的文件大小的任何提示?它是否必须与文件中的"''r"和"'"字符有关?此外,我还有以下一行:

    int bytesLoaded = 0;

如果文件是 1GB 大,我是否必须使用"长"代替?谢谢你的时间!

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

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

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

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

也就是说,如果您打算将文件读取为字节序列(不考虑行(,则应使用 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"
    }
}

编辑:spender提出了一个关于字符编码的重要观点;你的代码应该只用于ASCII文本文件。如果您的文件是使用不同的编码编写的(当今最流行的是 UTF-8(,那么结果可能不正确。

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

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

这是被

ReadLine 吞噬的行尾,也可能是因为您的源文件的编码比 ASCII 更详细(也许是 UTF8?(。

int.MaxValue 2147483647,因此如果您的文件为>2GB,则使用 int for bytesLoaded 时会遇到问题。切换到long。毕竟,FileInfo.Length被定义为long

ReadLine 方法删除尾随行终止字符。