C# streamreader Read(char[] buffer, int index, int count) 方法在 streamreader 对象 Position 大于 buffersize 后无法从文件中读取
C# streamreader Read(char[] buffer, int index, int count) method fails to read from file after streamreader object Position is greater than buffersize
更新:
我可以确认以下行为是我造成的
做一些我之前没有指定的事情,我正在用 reader charPos 属性 手动播放,因此问题可以重命名:"How to screw up your working fine Read(buffer,int,int) method" 答案是简单地手动设置reader (SR1) 位置在流 (FSr) 之外的位置 buffersize(不要与读取操作缓冲区混淆):
循环之前(在原问题的代码中)
System.Reflection.FieldInfo charPos_private = typeof(StreamReader).GetField("charPos", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly);
并在循环内(在原始问题的代码中)
charPos_private.SetValue(SR1, string_index);
文件 reader 实际上读取到 1024,然后当文件流读取下一个 1024 个字符时它变为 0。我试图手动设置位置(因为我弄乱了一些模式)但我没有注意到它永远不会达到 1025。
然后,你就是这样把简单的事情搞砸的。
非常感谢所有评论!非常感激!我会将答案设置为包含有关如何正确执行此操作的示例的答案,如果不是我没有提到的那几行代码,我发布的代码也可以正常工作。
原题
第一次来这里,
我正在自学C#。我正在尝试使用 streamreader 从一个大的 UTF-8 Linux LF(结束于 \n)(一个 xml)逐个字符(或逐块)读取,并且我正在对它执行一些操作,然后将它逐个字符(或逐块)写入一个新文件。我有一个 streamreader 和 streamwriter.
我会文字说明,最后加点代码:
我正在查找流reader Read() 和 Read(char[] buffer, int index, int count) 方法对大文件执行不同的操作。我知道这两个只不过是调用同一个方法的两种不同方式(我也尝试过ReadBlock)但是情况是:Read()方法自动填充StreamReader对象ByteBuffer(数组)动态地,即当 StreamReader 对象 Position 达到默认的 bufferSize 参数(通常为 1024 或 4096)时,方法 自动 开始 缓冲下一个 1024 或 4096 或任何缓冲区大小。
但是 Read(char[] buffer, int index, int count) 不会自动执行此操作 因此当 StreamReader 对象 Position 达到缓冲区大小 +1 时它会抛出异常。即在 1025 位置或 4097 位置 (char) (System.IndexOutofRangeException on System.Buffer.InternalBlockCopy(Array src, Int32 srcOffsetBytes, Array dst, Int32 dstOffsetBytes, Int32 byteCount)) 或如果我尝试使用 Peek() 查看接下来的内容(System.IndexOutofRangeException on System.IO.StreamReader.Peek())。我的测试文件是 300 MB。
*问题是:如何让 Read(char[] buffer, int index, int count) 自动重新缓冲 ByteBuffer(StreamReader:非 Public 成员 ByteBuffer)以便有效地读取大于缓冲区大小的文件?或者换句话说:我如何使用 Read(buffer_search, 0, x_number_of_chars) 实际读取大文件? *
我的意思是我不知道我是否需要通过系统反射手动修改 ByteBuffer 以及我将如何做。它应该是自动的;手动重新缓冲对于一件简单的事情来说就像太多的工作。
在代码中:(我在这里解释了一些代码)
做类似的事情:
char current_char;
using (System.IO.FileStream FSw = new FileStream(sourcePath, FileMode.Create))
{
using (System.IO.StreamWriter SW1 = new StreamWriter(FSw, System.Text.Encoding.UTF8))
{
using (FileStream FSr = new FileStream(destinationPath, FileMode.Open))
{
using (StreamReader ofile_temp_chars = new StreamReader(fsr, System.Text.Encoding.UTF8))
{
while ((current_char = (char)SR1.Read()) != '\uffff')
{
SW1.Write(current_char);
}
}
}
}
}
代码成功,没有问题。大文件被读入写入新文件。
但是当我尝试指定要读取的字符数时(我实际上必须读取用户定义的字符数,我只是在这里展示一些代码,只读取一个字符以简化)然后我需要使用 Read(char[] buffer, int index, int count),像这样:
char[] buffer_search = new char[1]
using (System.IO.FileStream FSw = new FileStream(fePath, FileMode.Create))
{
using (System.IO.StreamWriter SW1 = new StreamWriter(FSw, System.Text.Encoding.UTF8))
{
using (FileStream FSr = new FileStream(fPath, FileMode.Open))
{
using (StreamReader ofile_temp_chars = new StreamReader(fsr, System.Text.Encoding.UTF8))
{
while (SR1.Peek() != -1)
{
SR1.Read(buffer_search, 0, 1);
SW1.Write(buffer_search[0]);
}
}
}
}
}
当流reader 对象 Position 达到并超过缓冲区大小(即 1025、4097)等时,该代码将以异常结束((System.IndexOutofRangeException on System.IO.StreamReader.Peek() )等。 .. 显然是从它在缓冲区上的内容而不是在文件本身上偷看,并且不会自动重新缓冲导致在 ByteBuffer char[] 之外偷看。
如果我这样做:
char[] buffer_search = new char[1]
using (System.IO.FileStream FSw = new FileStream(fePath, FileMode.Create))
{
using (System.IO.StreamWriter SW1 = new StreamWriter(FSw, System.Text.Encoding.UTF8))
{
using (FileStream FSr = new FileStream(fPath, FileMode.Open))
{
using (StreamReader SR1 = new StreamReader(fsr, System.Text.Encoding.UTF8))
{
while (!end_of_file)
{
try { SR1.Read(buffer_search, 0, 1); }
catch { end_of_file = true; }
SW1.Write(buffer_search[0]);
}
}
}
}
}
然后我将得到一个仅包含 1024 个字符或缓冲区大小的文件。将抛出的异常(捕获)将是:
System.IndexOutOfRangeException on System.Buffer.InternalBlockCopy(Array src, Int32 srcOffsetBytes, Array dst, Int32 dstOffsetBytes, Int32 byteCount)
在 System.IO.StreamReader.Read(Char[] 缓冲区,Int32 索引,Int32 计数)
所以在这两种情况下,结果是相同的,缓冲区没有从文件中获取新数据,这是由 Read() 和 ReadLine() 方法自动处理的。
像增加缓冲区大小这样的简单解决方案将不起作用,因为我的文件有数百 MB,而且我正在努力提高内存效率...(或者更简单,比如使用 Read(),因为我需要使用 Read(buffer, 0, x_number_of_chars)。这应该是一件简单的事情,但花费的时间比预期的要长。
感谢您的帮助,
真不清楚你在问什么。但是,如果你想从一个流 reader 中读取任意数量的字符并将它们写入写入器,这可行:
int bytesRead;
do
{
bytesRead = SR1.Read(buffer_search, 0, buffer_search.Length);
if (bytesRead > 0)
{
// TODO: process buffer_search in some way.
SW1.Write(buffer_search, 0, bytesRead);
}
} while (bytesRead > 0);
这将在需要时将新字符读入内部流写入器缓冲区。
更新:
我可以确认以下行为是我造成的 做一些我之前没有指定的事情,我正在用 reader charPos 属性 手动播放,因此问题可以重命名:"How to screw up your working fine Read(buffer,int,int) method" 答案是简单地手动设置reader (SR1) 位置在流 (FSr) 之外的位置 buffersize(不要与读取操作缓冲区混淆):
循环之前(在原问题的代码中)
System.Reflection.FieldInfo charPos_private = typeof(StreamReader).GetField("charPos", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly);
并在循环内(在原始问题的代码中)
charPos_private.SetValue(SR1, string_index);
文件 reader 实际上读取到 1024,然后当文件流读取下一个 1024 个字符时它变为 0。我试图手动设置位置(因为我弄乱了一些模式)但我没有注意到它永远不会达到 1025。
然后,你就是这样把简单的事情搞砸的。 非常感谢所有评论!非常感激!我会将答案设置为包含有关如何正确执行此操作的示例的答案,如果不是我没有提到的那几行代码,我发布的代码也可以正常工作。
原题
第一次来这里,
我正在自学C#。我正在尝试使用 streamreader 从一个大的 UTF-8 Linux LF(结束于 \n)(一个 xml)逐个字符(或逐块)读取,并且我正在对它执行一些操作,然后将它逐个字符(或逐块)写入一个新文件。我有一个 streamreader 和 streamwriter.
我会文字说明,最后加点代码:
我正在查找流reader Read() 和 Read(char[] buffer, int index, int count) 方法对大文件执行不同的操作。我知道这两个只不过是调用同一个方法的两种不同方式(我也尝试过ReadBlock)但是情况是:Read()方法自动填充StreamReader对象ByteBuffer(数组)动态地,即当 StreamReader 对象 Position 达到默认的 bufferSize 参数(通常为 1024 或 4096)时,方法 自动 开始 缓冲下一个 1024 或 4096 或任何缓冲区大小。
但是 Read(char[] buffer, int index, int count) 不会自动执行此操作 因此当 StreamReader 对象 Position 达到缓冲区大小 +1 时它会抛出异常。即在 1025 位置或 4097 位置 (char) (System.IndexOutofRangeException on System.Buffer.InternalBlockCopy(Array src, Int32 srcOffsetBytes, Array dst, Int32 dstOffsetBytes, Int32 byteCount)) 或如果我尝试使用 Peek() 查看接下来的内容(System.IndexOutofRangeException on System.IO.StreamReader.Peek())。我的测试文件是 300 MB。
*问题是:如何让 Read(char[] buffer, int index, int count) 自动重新缓冲 ByteBuffer(StreamReader:非 Public 成员 ByteBuffer)以便有效地读取大于缓冲区大小的文件?或者换句话说:我如何使用 Read(buffer_search, 0, x_number_of_chars) 实际读取大文件? *
我的意思是我不知道我是否需要通过系统反射手动修改 ByteBuffer 以及我将如何做。它应该是自动的;手动重新缓冲对于一件简单的事情来说就像太多的工作。
在代码中:(我在这里解释了一些代码)
做类似的事情:
char current_char;
using (System.IO.FileStream FSw = new FileStream(sourcePath, FileMode.Create))
{
using (System.IO.StreamWriter SW1 = new StreamWriter(FSw, System.Text.Encoding.UTF8))
{
using (FileStream FSr = new FileStream(destinationPath, FileMode.Open))
{
using (StreamReader ofile_temp_chars = new StreamReader(fsr, System.Text.Encoding.UTF8))
{
while ((current_char = (char)SR1.Read()) != '\uffff')
{
SW1.Write(current_char);
}
}
}
}
}
代码成功,没有问题。大文件被读入写入新文件。
但是当我尝试指定要读取的字符数时(我实际上必须读取用户定义的字符数,我只是在这里展示一些代码,只读取一个字符以简化)然后我需要使用 Read(char[] buffer, int index, int count),像这样:
char[] buffer_search = new char[1]
using (System.IO.FileStream FSw = new FileStream(fePath, FileMode.Create))
{
using (System.IO.StreamWriter SW1 = new StreamWriter(FSw, System.Text.Encoding.UTF8))
{
using (FileStream FSr = new FileStream(fPath, FileMode.Open))
{
using (StreamReader ofile_temp_chars = new StreamReader(fsr, System.Text.Encoding.UTF8))
{
while (SR1.Peek() != -1)
{
SR1.Read(buffer_search, 0, 1);
SW1.Write(buffer_search[0]);
}
}
}
}
}
当流reader 对象 Position 达到并超过缓冲区大小(即 1025、4097)等时,该代码将以异常结束((System.IndexOutofRangeException on System.IO.StreamReader.Peek() )等。 .. 显然是从它在缓冲区上的内容而不是在文件本身上偷看,并且不会自动重新缓冲导致在 ByteBuffer char[] 之外偷看。
如果我这样做:
char[] buffer_search = new char[1]
using (System.IO.FileStream FSw = new FileStream(fePath, FileMode.Create))
{
using (System.IO.StreamWriter SW1 = new StreamWriter(FSw, System.Text.Encoding.UTF8))
{
using (FileStream FSr = new FileStream(fPath, FileMode.Open))
{
using (StreamReader SR1 = new StreamReader(fsr, System.Text.Encoding.UTF8))
{
while (!end_of_file)
{
try { SR1.Read(buffer_search, 0, 1); }
catch { end_of_file = true; }
SW1.Write(buffer_search[0]);
}
}
}
}
}
然后我将得到一个仅包含 1024 个字符或缓冲区大小的文件。将抛出的异常(捕获)将是: System.IndexOutOfRangeException on System.Buffer.InternalBlockCopy(Array src, Int32 srcOffsetBytes, Array dst, Int32 dstOffsetBytes, Int32 byteCount) 在 System.IO.StreamReader.Read(Char[] 缓冲区,Int32 索引,Int32 计数)
所以在这两种情况下,结果是相同的,缓冲区没有从文件中获取新数据,这是由 Read() 和 ReadLine() 方法自动处理的。
像增加缓冲区大小这样的简单解决方案将不起作用,因为我的文件有数百 MB,而且我正在努力提高内存效率...(或者更简单,比如使用 Read(),因为我需要使用 Read(buffer, 0, x_number_of_chars)。这应该是一件简单的事情,但花费的时间比预期的要长。
感谢您的帮助,
真不清楚你在问什么。但是,如果你想从一个流 reader 中读取任意数量的字符并将它们写入写入器,这可行:
int bytesRead;
do
{
bytesRead = SR1.Read(buffer_search, 0, buffer_search.Length);
if (bytesRead > 0)
{
// TODO: process buffer_search in some way.
SW1.Write(buffer_search, 0, bytesRead);
}
} while (bytesRead > 0);
这将在需要时将新字符读入内部流写入器缓冲区。