这是我关于读文件的第三个帖子了。现在问题更清楚了一点,主要还是借鉴了第一次发帖时,人家的解答来做的。
现在我要读一个超大的二进制文件大概1G左右,读取了之后要把里面的数据处理一下,并且保存到txt文件中,数据处理没问题,主要是读文件的问题。
1。这么大的文件,肯定不能全部一次读入到内存中去,所以,只能读一部分,处理完了,接下去读取。也就要分快读取数据。
关键代码如下
                        StatusLabel.Text = "正在读取原始数据";
                        FileStream fs = new FileStream(openADFile, FileMode.Open,FileAccess.Read);
                        BinaryReader br = new BinaryReader(fs);                        int bufferSize = 10240; //每次读取的字节数 每次读取1MB
                        byte[] buffer = new byte[bufferSize];                        long fileLength = fs.Length;//文件流的长度  StreadReader对象没有length方法
                        int readCount = (int)Math.Ceiling((double)(fileLength / bufferSize)); //需要对文件读取的次数
                        progressBar.Maximum = readCount;
                        progressBar.Visible = true;
                        int readIndex = 0;//当前已经读取的次数
                        statusStrip.Update();
                        do
                        {
                            buffer = br.ReadBytes(bufferSize);
                            list.AddRange(buffer);
                            buffer = null;
///deltData()为处理数据list的递归调用方法,处理过的list会remove一点,只到长度不能符合要求位置,再继续读取一些进去。
                            deleData();
                            readIndex++;
                            progressBar.PerformStep();
                            progressBar.Invalidate();
                            GC.Collect();
                        } while (readIndex < readCount);
                        br.Close();
                        fs.Close();
                        list.Clear();
                        progressBar.Visible = false;
                        progressBar.Value = 0;
                        progressBar.Maximum = 0;
                        StatusLabel.Text = "读取完成";
                        statusStrip.Invalidate();
deleData()方法/// <summary>
        /// 处理list数据
        /// </summary>
        /// <param name="list"></param>
        private void deleData()
        {
            if (list.Count >= 86)
            {
                if (list[0] == 255 && list[85] == 255) ///头尾是否为数据头0XFF
                {
                    if (0 < list[1] && list[1] < 5 && list[2] < 25 && list[2] >= 0)
                    {
                        if (list[3] == 80)
                        {
                             //判断数据为正确的,保存下来。
                              createFile(list[1], index, line);
                              list.RemoveRange(0, 86);
                        }
                        else
                        {
                            list.RemoveAt(0);
                        }
                    }
                    else
                    {
                        list.RemoveAt(0);
                    }
                }
                else
                {
                    list.RemoveAt(0);
                }
                deleData();
            }
            else
            {
                return;
            }
        }createFile()方法  写数据到文本文件中去        /// <summary>
        /// 按照设备号,节号创建文件
        /// </summary>
        /// <param name="group"></param>
        /// <param name="index"></param>
        private void createFile(int group, int index, float[] line)
        {
            if (folderName != null)
            {
                string filename = folderName + "\\" + group + "\\" + (index + 1) + ".log";
                try
                {
                    FileStream fi;
                    if (File.Exists(filename))
                    {
                        fi = new FileStream(@filename, FileMode.Append);
                    }
                    else
                    {
                        fi = new FileStream(@filename, FileMode.Create);
                    }                    using (StreamWriter w = new StreamWriter(fi))
每次都是这个地方报错,如果buffersize设置的太大的话会爆一个StackOverflowException,如果设置小了,运行了一段时间又会爆一个ContextSwtichDeadlock错误,
                    {
                        for (int i = 0; i < line.Length; i++)
                        {
                            w.Write(line[i] + ",");
                        }
                        w.WriteLine();
                        w.Flush();
                        w.Close();
                        fi.Close();
                    }
                    PlusNum(group, index);
                }
                catch (Exception ex)
                {
                    port.errorData(ex.Message);
                    MessageBox.Show(ex.Message);
                }
                counter++;
            }
       }这里的buffersize表示一次读取的字节数,我如果设置成1024的话,那就是每次读取1KB,要是这样读的话,1G的文件处理起来非常慢。我都等不下去了,如果把buffersize改大一点,我想每次读取1MB,本来1MB,我想应该不算大的,deleData()方法里面会调用createFile()里面写文件的StreamWrite会报错。StackOverflowException。

解决方案 »

  1.   

    问题相关帖子:
    C# 读取超大文本文件(2G左右),求解决办法!
    http://topic.csdn.net/u/20101217/13/c2396c5a-4cc1-4a17-8b3d-7db317f39c58.html
    关于C#读取二进制文件,以及怎么处理数据,给点意见。
    http://topic.csdn.net/u/20110104/14/1554dc50-adf2-45a0-a79b-71dad9754ac1.html?seed=1951352104&r=71020225#r_71020225
      

  2.   

    解决死锁难题 ContextSwitchDeadlockhttp://blog.csdn.net/mustbelove/archive/2007/07/29/1714805.aspx
      

  3.   

    那是因为你buffersize 太小 太过频繁IO操作....  你试想一下1G 文件 你, Open 了多少次
    你试下,不在调试状态下运行是否会出错....
    你也可以尝试着把createFile中的FileStream放在全局变量里,在
    do 上面Open一次
    {
           
    } while (readIndex < readCount);
    下面Close一次
      

  4.   


    就是这样的啊,我读取文件的时候,firestream是放在do..while()外面的啊,只是在dowhile调用的方法里面有写文件的方法。。
      

  5.   

                            FileStream fs = new FileStream(openADFile, FileMode.Open,FileAccess.Read);
                            BinaryReader br = new BinaryReader(fs);                        int bufferSize = 10240; //每次读取的字节数 每次读取1MB
                            byte[] buffer = new byte[bufferSize];                        long fileLength = fs.Length;//文件流的长度  StreadReader对象没有length方法
                            int readCount = (int)Math.Ceiling((double)(fileLength / bufferSize)); //需要对文件读取的次数
                            progressBar.Maximum = readCount;
                            progressBar.Visible = true;
                            int readIndex = 0;//当前已经读取的次数
                            statusStrip.Update();
                            do
                            {
                                buffer = br.ReadBytes(bufferSize);
                                list.AddRange(buffer);
                                buffer = null;
    ///deltData()为处理数据list的递归调用方法,处理过的list会remove一点,只到长度不能符合要求位置,再继续读取一些进去。
                                deleData();
                                readIndex++;
                                progressBar.PerformStep();
                                progressBar.Invalidate();
                                GC.Collect();
                            } while (readIndex < readCount);
                            br.Close();
                            fs.Close();
    我就是这样的额,deleData()里面还会调用方法去执行写文件的操作