C# 如何根据换行将超大TXT文件分割成若干个小文件

.Net技术 码拜 10年前 (2015-07-11) 1378次浏览 0个评论
 

TXT文件,3.2g,如何把这个文件分割成若干个小文件?

分割不能切开某一个时间线的数据。

11:11,1,2,3,4,5,6,7,8,9,0
11:12,1,2,3,4,5,6,7,8,9,0
11:13,1,2,3,4,5,6,7,8,9,0
11:14,1,2,3,4,5,6,7,8,9,0
11:15,1,2,3,4,5,6,7,8,9,0

例如上面的数据,如何按行分割,要求一行时间线的数据不能切开(也就是换行分割)?

最好给个源码看看,我现在分割可以但是没根据换行分割,而且分割的时候会超时

 
你就用换行符分割啊!超时估计是你的文档太大,但是应该还在运行的.你可以看分割后的文档有没有增加
 
每行长度一样?
那就计算分割文件SIZE,直接二进制操作就快了
 

            FileStream fsIn = new FileStream(fileIn, FileMode.Open, FileAccess.Read);
            FileStream fsOut = new FileStream(fileOut, FileMode.OpenOrCreate, FileAccess.Write);

                int bufferLen = 4096*1000;
                byte[] buffer = new byte[bufferLen];
                int bytesRead;
                bytesRead = fsIn.Read(buffer, 0, bufferLen);
                fsOut.Write(buffer, 0, bytesRead);

 

超时之后就不会分割了,程序都报错了,没继续运行

 

每行长度不是一样的,这只是测试的数据,真正的数据不是这样的

 

protected void Button1_Click(object sender, EventArgs e)
        {
            int iFileSize = 10000 * 1024;
            FileStream TempStream = null;
            BinaryWriter TempWriter=null;
            //根据选择来设定分割的小文件的大小
            string filepath = @"Z:\ftpfoot\ksd_rtx\KSD_RTX_140131.txt";
            //反之则在计算机创建目录
            FileStream SplitFileStream = new FileStream(filepath, FileMode.Open);
            //以文件的全路对应的字符串和文件打开模式来初始化FileStream文件流实例
            BinaryReader SplitFileReader = new BinaryReader(SplitFileStream);
            //以FileStream文件流来初始化BinaryReader文件阅读器
            byte[] TempBytes;
            //每次分割读取的最大数据
            int iFileCount = (int)(SplitFileStream.Length / iFileSize);
            //小文件总数
            //progressBar1.Maximum = iFileCount;
            if (SplitFileStream.Length % iFileSize != 0) iFileCount++;
            string[] TempExtra = filepath.Split(""."");
            /* 循环将大文件分割成多个小文件 */
            for (int i = 1; i <= iFileCount; i++)
            {
                string sTempFileName = @"Z:\ftpfoot\ksd_rtx" + i.ToString().PadLeft(4, ""0"") + "." + TempExtra[TempExtra.Length - 1]; //小文件名
                //确定小文件的文件名称
                TempStream = new FileStream(sTempFileName, FileMode.OpenOrCreate);
                //根据文件名称和文件打开模式来初始化FileStream文件流实例
                TempWriter = new BinaryWriter(TempStream);
                //以FileStream实例来创建、初始化BinaryWriter书写器实例
                TempBytes = SplitFileReader.ReadBytes(iFileSize);
                //从大文件中读取指定大小数据
                TempWriter.Write(TempBytes);
                //把此数据写入小文件
                TempWriter.Close();
                //progressBar1.Value = 0;
                //String fileName = @"Z:\ftpfoot\ksd_rtx\KSD_RTX_140131.txt";
                //FilePartition objFp = new FilePartition(fileName);
                //if (objFp.OnPartitionFile())
                //    Response.Write(String.Format("共切割成{0}个文件.", objFp.FileCount));
            }
            if (SplitFileReader != null) SplitFileReader.Close();
            if (TempWriter != null) TempWriter.Close();
            if (TempStream != null) TempStream.Close();
        }
 
这个给力.net对于大文件 我一直无解
来学习下
 
我以前写过一个按行读取分割的,分割几百MB的文档没问题,你的几GB不知道行不行.
 
sr.ReadLine()

20分

string name = Path.GetFileNameWithoutExtension(openFileDialog.FileName);
                saveFileDialog.Filter = "文本文件(*.txt)|*.txt";
                int line = 0,num=0;
                if (!Directory.Exists(dizhi.Text + "\" + name))
                {
                    Directory.CreateDirectory(dizhi.Text + "\" + name);
                }
                string hang;
                StreamReader sr = new StreamReader(mubiao.Text, System.Text.Encoding.GetEncoding("UTF-8"));
                while ((hang = sr.ReadLine()) != null)
                {
                    line++;
                    StreamWriter sw = new StreamWriter(dizhi.Text + "\" + name + "\A" + num + ".txt", true, System.Text.Encoding.GetEncoding("UTF-8"));
                    sw.WriteLine(hang);
                    sw.Close();
                    if (line == 2000)
                    {
                        line = 0;
                        num++;

                    }
                }
 
看来执行时间短不了
3.2G 复制黏贴一下 就要多长时间啊 还要分割出来。
 

正常的分割要不了多久,但是根据换行分割就不知道了

 

效果是达到了,但是速度貌似有点慢啊

 
没有程序,说说我的思路:
使用BinaryReader :
首先:假设截取的文件大小为1M(1024*1024 字节),从头读取。
binaryReader.BaseStream.Position = 1024*1024-1;
读取 1024*1024-1 处的字节判断是不是 换行符,不是的话,读取1024*1024 处,知道为换行符为止(假设为止为B)
则,读取0-B
binaryReader.ReadBytes(B-0+1)个字节并保存。
然后从B+1 处读取,知道结束。
 
/// <summary>
/// 分割大文件成独立小文件并保存小文件至指定目录
/// </summary>
/// <param name=”splitunit”>分割单位(KB,MB)</param>
/// <param name=”intFlag”>分割大小</param>
/// <param name=”destCatalog”>保存路径</param>
/// <param name=”sourcefileurl”>源文件路径</param>
/// <returns>true表示分割成功,false表示分割失败</returns>
public static bool SplitFile(string splitunit, int intFlag, string destCatalog, string sourcefileurl)
{
bool suc = false;
try
{
int iFileSize = 0;
switch (splitunit)
{
case “Byte”:
iFileSize = intFlag;
break;
case “KB”:
iFileSize = 1024 * intFlag;
break;
case “MB”:
iFileSize = 1024 * 1024 * intFlag;
break;
default:
iFileSize = 1024 * 1024 * 1024 * intFlag;
break;
}
FileStream SplitFileStream = new FileStream(sourcefileurl, FileMode.Open);
BinaryReader SplitFileReader = new BinaryReader(SplitFileStream);
Byte[] TempBytes;
int ifilecount = (int)(SplitFileStream.Length / iFileSize);
if (SplitFileStream.Length % iFileSize != 0)
{
ifilecount++;
}
for (int i = 1; i <= ifilecount; i++)
{
string sTempFileName = destCatalog + “\” + i.ToString().PadLeft(4, “”0″”) + Path.GetExtension(destCatalog);
FileStream TempStream = new FileStream(sTempFileName, FileMode.OpenOrCreate);
BinaryWriter bw = new BinaryWriter(TempStream);
TempBytes = SplitFileReader.ReadBytes(iFileSize);
bw.Write(TempBytes);
bw.Close();
TempStream.Close();
}
SplitFileStream.Close();
SplitFileReader.Close();
suc = true;
}
catch { suc = false; }
return suc;
}
 

因为是逐行读取,你尝试下上面的方法吧

 

这个方法跟我写的如出一辙,快是很快,但是分割后的文件最后一条数据可能是断掉的,没有根据换行分割

 

这个思路我感觉可以,但是根据字节怎么得到文本里的内容呢

 

这容易 先用FileStream读取文件长度 然后设定每个文件长度大小为多少
假如每个文件为1M左右
那就是 文件个数 =FileLength/1024/1024;
接下来利用上面的Position 直接定位 第一个文件就是0 到 (1*1024 *1024)字节
先读取这个0- (1*1024 *1024)字节,然后判断(1*1024 *1024)处的两个字节是不是\r\n
代码可以这样
write(0,Position);把大块先写到文件里
while(true)
{
byte[] buff=new byte[1];这里从Position后每次读1个字节
stream.Read(buff,0,1);
write(buff)把读取到的写到文件中
if(buff[0]=””\n””)
{
break;
}
}
然后直接利用Position即可直接向下读
下面做第二个文件的处理
这是先分块的

另外一种是直接
FileStream stream
long MaxLength
FileStream newFile=new 第一个文件
while(true)
{
每次读取两个字节
写入文件块
if(这两个字节是否为\r\n && 是否超出MaxLength)
{
newFile =new (新文件);
}

}

 
就这个你用FileStream 的类
fs.Read();
fs.ReadByte();
基本是不会占内存的方法读取 他是直接定位到文件某处读取几个字节,

不像其他的类ReadLine()这样是先加载整个文件然后再读取

所以造成你的程序无法加载大文件,用FileStream几个字节几个字节读是不会有问题 的所以我上面说的你读两个字节就可以了,

 
我根据你第一个方法读取我的byte字节数组,读不到换行符,也读不到内容,只是一下字节数字
 

换行符转换成字节byte1 如果等于binaryReader.ReadByte()获得字节,说明就是换行符,就可读取一段数据了

 

或者将你获得的字节转化成字符串和换行符比较

10分

 /// <summary>
        /// 分割文件
        /// </summary>
        /// <param name="fileName">原文件路径</param>
        /// <param name="outputFileName">目标文件路径</param>
        /// <param name="childFileLong">子文件大小(M)</param>
        private void SplitText(string fileName,string outputFileName, long childFileLong)
        {
            FileStream fileStream = new FileStream(fileName, FileMode.Open);
            BinaryReader binaryReader = new BinaryReader(fileStream);
            long childFilecount = 1024 * 1024;
            long allCount = fileStream.Length;

            int outputFileNumber = 0;
            long startPositon = 0;
            binaryReader.BaseStream.Position =startPositon+ childFilecount - 1;
            while (binaryReader.BaseStream.Position <= allCount)
            {
                while (Encoding.Default.GetString(new byte[] { binaryReader.ReadByte() }) != "/n" && binaryReader.BaseStream.Position<allCount-1)
                {
                    binaryReader.BaseStream.Position++;
                }

                FileStream fileStreamOut = new FileStream(outputFileName+outputFileNumber.ToString(), FileMode.CreateNew);
                using (BinaryWriter binaryWriter = new BinaryWriter(fileStreamOut))
                {
                    binaryWriter.Write(binaryReader.ReadBytes((int)(binaryReader.BaseStream.Position - startPositon + 1)));
                }

                startPositon = binaryReader.BaseStream.Position + 1;
                binaryReader.BaseStream.Position = startPositon + childFilecount - 1;
                outputFileNumber++;

            }

            binaryReader.Close();


        }
 

以上代码供你参考,没有测试。如果子文件也比较大,为了避免占用大量内存空间,
binaryWriter.Write(binaryReader.ReadBytes((int)(binaryReader.BaseStream.Position – startPositon + 1)));这部分需要再进行处理,分割成更小的片段读取写入。

 
直接用FileStream一边读取一边写入,遇到换行符的时候新建文件!
 

while (binaryReader.BaseStream.Position <= allCount)
            {
                while (Encoding.Default.GetString(new byte[] { binaryReader.ReadByte() }) != "/n" && binaryReader.BaseStream.Position<allCount-1)
                {
                    binaryReader.BaseStream.Position++;
                }

这两个循环次数太多了,我得到的文件allCount 长度是13亿多,但是binaryReader.BaseStream.Position的position值只有100多万这样也很慢

 

才30分呀,要是200分就给你实现一个

 
正常分割什么意思?先分成几个适当的文件,在按行处理
 
using System;
using System.IO;
using System.Text;

namespace File_Read
{
class FileRead
{
static void Main(string[] args)
{
string sourcePath = @”C:\Big File\0601-0604.txt”;
string targetDirectory = @”D:\Splited File”;
ReadData(sourcePath, targetDirectory);
// Console.ReadLine();
}

static void ReadData(string sourcePath,string targetDirectory)
{
FileStream fs = new FileStream(sourcePath, FileMode.Open, FileAccess.Read);
StreamReader sr = new StreamReader(fs, Encoding.Default);
sr.BaseStream.Seek(0, SeekOrigin.Begin);
string line = string.Empty;
int seg=0;

while (line != null)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 350; i++)
{
line = sr.ReadLine();
if (line == null)
break;
else
sb.AppendLine(line);
}
seg++;
string targetPath = targetDirectory + “\” + Path.GetFileNameWithoutExtension(sourcePath) + “_” + seg.ToString() + Path.GetExtension(sourcePath);
sb.AppendLine();
WriteData(sb.ToString(), targetPath);
}
sr.Close();
fs.Close();
}

static void WriteData(string str, string path)
{
FileStream aFile = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
StreamWriter sw = new StreamWriter(aFile);
sw.Write(str);
sw.Close();
aFile.Close();
}
}
}


CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明C# 如何根据换行将超大TXT文件分割成若干个小文件
喜欢 (0)
[1034331897@qq.com]
分享 (0)

文章评论已关闭!