问题的起因如下:
  我们需要用StreamWrite来读取一个文件,但是用StreamWrite 原本的ReadLine方法无法得到正确的行数。在MSDN中有一段描述如下:
--------
行的定义是:后跟换行符 ("\n") 的一个字符序列,或后面紧跟换行符 ("\r\n") 的回车。返回的字符串不包含终止回车或换行符。如果到达了输入流的末尾,返回值为空引用(Visual Basic 中为 Nothing)。
--------而我们的需求中行的定义是\r\n, 而\n不能作为单独的行,所以,用StreamReader的ReadLine方法得不到我们需要的结果。因此我们对StreamRead类进行封装。重写ReadLine方法,但是很快就发现无法实现,现把问题贴出来给大家,希望能集思广益。
代码如下(C++.NET 托管,和C#以没有什么区别)
PostlogStreamReader.h
--------------------#pragma onceusing namespace System;
using namespace System::IO;
using namespace System::Text;
using namespace System::Threading;namespace TestNameSpace
{
public __gc class PostLogStreamReader: public StreamReader
{
private: String *m_strline;
private: Thread *m_thread;
private: bool m_bIsReadToEnd;
private: bool m_bIsContinue;
private: bool m_bPrepareLineFinished; public: PostLogStreamReader(String *strFileName, Encoding *encoding, bool bdetectencoding) : 
StreamReader(strFileName, encoding, bdetectencoding)
{
m_bIsReadToEnd = false;
m_bIsContinue = false;
m_bPrepareLineFinished = false;
} public: ~PostLogStreamReader(void)
{
} public: void StartReader()
{
m_thread = new Thread(new ThreadStart(this, ShowLines));
m_thread->Start();
} public: void ShowLines()
{
String *line = String::Empty;
char cur = '\0';
char pre = '\0'; String *strtmp = String::Empty; while (Peek() >= 0)
{
m_bPrepareLineFinished = false;
cur = Read();
if ('\r' != cur && '\n' != cur)
{
char t[] = {cur};
strtmp = new String(t);
line = String::Concat(line, strtmp);
}
if ('\r' == pre && '\n' == cur)
{
//Console::WriteLine(line);
m_strline = line;
line = String::Empty;
m_bPrepareLineFinished = true;
m_bIsContinue = false;
ReadWait();
}
pre = cur;
} m_bIsReadToEnd = true;
Close();
} public: void ReadWait()
{
while (!m_bIsContinue)
{
Console::WriteLine(S"thread pause --start--!!");
m_thread->Sleep(1);
Console::WriteLine(S"thread pause --end ---!!");
} m_bPrepareLineFinished = false;
} public: void ContinueReader()
{
m_bIsContinue = true;
} public: String *GetLineText()
{
return m_strline;
} public: bool IsReaderToEnd()
{
return m_bIsReadToEnd;
} public: bool PrepareLineFinished()
{
return m_bPrepareLineFinished;
} };//end class
}//end namespace主函数
------------------
int _tmain()
{
(Thread::CurrentThread)->ApartmentState = ApartmentState::STA; String *strPostLogFileName = S"c:\\temp\\postlog.txt"; StreamWriter *sw = new StreamWriter(S"c:\\temp\\test.txt", true); PostLogStreamReader *reader = new PostLogStreamReader(strPostLogFileName, Encoding::Default, true);
reader->StartReader();
// Thread::CurrentThread->Sleep(1000); while (!reader->IsReaderToEnd())
{
while (!reader->PrepareLineFinished())
{
Thread::CurrentThread->Sleep(10);
}
String *line = reader->GetLineText();

sw->WriteLine(line);
reader->ContinueReader();
} sw->Close();
return 0;}结果非常让人吃惊,test.txt既然有100多M。
而且涉及到线程的问题,比较困惑,谢谢各位。

解决方案 »

  1.   

    在读到stream了之后用Regex将需求中行的定义是\r\n替换成ReadLine可以接受的行的定义格式再操作不行吗?
      

  2.   

    to Tiger_zhao:
       我们就是按照判断\r\n来处理的,问题是我们无法实现像Readline这样的功能,ReadLine在读取完之后处于一个等待状态,然后等待调用下一次读取。怎样协调这两者之间的关系(StreamReader的读取线程和调用方的主线程)
    to hainang1234:
        直接读完要考虑的东西比较多,比如占用了太多的内存,并且在处理的时候速度也比较慢,所以我们一开始就不考虑这种方式。
      

  3.   

    to all:其他更多的想法和实现,谢谢
      

  4.   

    奇怪的需求,不过顶一下。
    ReadLine在读取完之后处于一个等待状态
    这句话不怎么明白,我觉得只有在键盘输入的时候ReadLine会等待,但是键盘是不容易输入\n的。
      

  5.   

    to zhy0101:
    ReadLine在读取完之后处于一个等待状态
    -------
    补充解释如下:
    例如一个文件有5行
    line1
    line2
    line3
    line4
    line5
    那么当我们有了一个streamwriter对象并且打开了该文件,我们习惯用如下代码处理while ((line = streamwriter.ReadLine()) != null)
    {     //do other thing here
    }那么当用户第一次ReadLine之后,程序正在处理while里面的代码的时候,streamwrite在做什么呢?那么第2次当用户读取ReadLine的时候,他又知道是第2行,而不是第3行呢?
      

  6.   

    #include "stdafx.h"#using <mscorlib.dll>using namespace System;using namespace System::IO;using namespace System::Text;public __gc class  MyReader{public:        MyReader(String* filename){sr = new StreamReader(filename);}        String* ReadLine()        {                StringBuilder *sb = new StringBuilder();                int p=0;                while(sr->Peek() >= 0)                {                        int t = sr->Read();                        if(p==13 && t== 10)                            return sb->ToString();                        else                            p=t;                       sb->Append(Convert::ToChar(t));                }                return sb->ToString();        }        int Peek()        {  return sr->Peek();}private:        StreamReader* sr; }; int _tmain(){    try        {                StreamWriter* sw = new StreamWriter("d:\\bbb.txt");                sw->Write("dsfs23404\r\n");                sw->Write("abcaaaaa\naaaa\r\naaa");                sw->Close();                MyReader * mr = new MyReader("d:\\bbb.txt");                               while(mr->Peek() >= 0)                {                        Console::WriteLine( "***New line***");                        Console::WriteLine(mr->ReadLine());                }}        catch(Exception* ex)        {        }            return 0;}