c++ 读取文件中的指定行

Lawake 2013-08-30 04:35:41
文件中都是正整数,共20万行,1235列,131G
都是0-255之间的整数。
我每次想提取某一行
在网上都是把文件全部读进内存后再取某一行,但是不适用于这种大数据的情况。
不知道大家有没有什么好方法呢?请帮助,谢谢!!!
...全文
1491 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
todd_leftcode 2013-09-01
  • 打赏
  • 举报
回复
做一个索引文件, 记录下每行开始的位置和长度, 然后读的时候先从索引文件获取某行的位置和长度, 再对数据文件执行seek, 然后按从索引文件中得到的长度读取一行。
大尾巴猫 2013-09-01
  • 打赏
  • 举报
回复
引用 12 楼 Lawake 的回复:
嗯嗯,您关于二进制文件的我明白了。 但是我的数据虽然每行个数相同,但是所占字节数不同,比如1占一个字节,255占3个字节。假设我想取第二行,我并不知道第一行有多少个字节,就无法用seekg函数跳过。不知道我说明白了没 您有什么好办法吗?
去网上搜索有关二进制读写文件的文章,不难。 二进制写文件能保证每个整数占用相同的字节,所以能计算出要读取数据的相对位置。 比如用1个字节表示0-255的整数,一行有1000个,你就知道第n行从哪里开始读。
Lawake 2013-09-01
  • 打赏
  • 举报
回复
引用 11 楼 ananluowei 的回复:
[quote=引用 10 楼 Lawake 的回复:] [quote=引用 9 楼 ananluowei 的回复:] [quote=引用 7 楼 Lawake 的回复:] [quote=引用 5 楼 ananluowei 的回复:] [quote=引用 1 楼 damingg 的回复:] 每行的字节数固定么? 如果是的,那么可以试试seek
+1 如果每行数字不对齐,或者说每行的长度不一致,只能从头一行行读,自己计数。[/quote] 嗯,我想过这个方法,但是数据量太大了,131G,我每行都要处理,那么处理到最后一行的时候还是相当与把所有数据都读进去了,肯定是不行的~~~~[/quote] 顺序读一次,写成二进制格式,接下来随机读写就如意了。[/quote] 您是说把0-255存成01000。。的形式吗?这样得到每行固定的字节数? [/quote] 二进制存储不是存储成01000的样子,那还是文本文件。是存储成像exe文件那样的16进制的数字,不能用文本文件打开,通俗的说,文本方式存储的是可见的字符,二进制存储的是00 01 FF这样的机器码。 65这个整数,文本方式存,看到65两个数字,二进制方式存,看到1个字母'A' 你这个例子很简单,都是0-255的数字,只要用unsigned char来表示1个数字就行了。只要每行数据个数相同,就可以随机读写。[/quote] 嗯嗯,您关于二进制文件的我明白了。 但是我的数据虽然每行个数相同,但是所占字节数不同,比如1占一个字节,255占3个字节。假设我想取第二行,我并不知道第一行有多少个字节,就无法用seekg函数跳过。不知道我说明白了没 您有什么好办法吗?
大尾巴猫 2013-09-01
  • 打赏
  • 举报
回复
引用 10 楼 Lawake 的回复:
[quote=引用 9 楼 ananluowei 的回复:] [quote=引用 7 楼 Lawake 的回复:] [quote=引用 5 楼 ananluowei 的回复:] [quote=引用 1 楼 damingg 的回复:] 每行的字节数固定么? 如果是的,那么可以试试seek
+1 如果每行数字不对齐,或者说每行的长度不一致,只能从头一行行读,自己计数。[/quote] 嗯,我想过这个方法,但是数据量太大了,131G,我每行都要处理,那么处理到最后一行的时候还是相当与把所有数据都读进去了,肯定是不行的~~~~[/quote] 顺序读一次,写成二进制格式,接下来随机读写就如意了。[/quote] 您是说把0-255存成01000。。的形式吗?这样得到每行固定的字节数? [/quote] 二进制存储不是存储成01000的样子,那还是文本文件。是存储成像exe文件那样的16进制的数字,不能用文本文件打开,通俗的说,文本方式存储的是可见的字符,二进制存储的是00 01 FF这样的机器码。 65这个整数,文本方式存,看到65两个数字,二进制方式存,看到1个字母'A' 你这个例子很简单,都是0-255的数字,只要用unsigned char来表示1个数字就行了。只要每行数据个数相同,就可以随机读写。
Lawake 2013-09-01
  • 打赏
  • 举报
回复
引用 9 楼 ananluowei 的回复:
[quote=引用 7 楼 Lawake 的回复:] [quote=引用 5 楼 ananluowei 的回复:] [quote=引用 1 楼 damingg 的回复:] 每行的字节数固定么? 如果是的,那么可以试试seek
+1 如果每行数字不对齐,或者说每行的长度不一致,只能从头一行行读,自己计数。[/quote] 嗯,我想过这个方法,但是数据量太大了,131G,我每行都要处理,那么处理到最后一行的时候还是相当与把所有数据都读进去了,肯定是不行的~~~~[/quote] 顺序读一次,写成二进制格式,接下来随机读写就如意了。[/quote] 您是说把0-255存成01000。。的形式吗?这样得到每行固定的字节数?
大尾巴猫 2013-08-31
  • 打赏
  • 举报
回复
引用 7 楼 Lawake 的回复:
[quote=引用 5 楼 ananluowei 的回复:] [quote=引用 1 楼 damingg 的回复:] 每行的字节数固定么? 如果是的,那么可以试试seek
+1 如果每行数字不对齐,或者说每行的长度不一致,只能从头一行行读,自己计数。[/quote] 嗯,我想过这个方法,但是数据量太大了,131G,我每行都要处理,那么处理到最后一行的时候还是相当与把所有数据都读进去了,肯定是不行的~~~~[/quote] 顺序读一次,写成二进制格式,接下来随机读写就如意了。
Lawake 2013-08-31
  • 打赏
  • 举报
回复
引用 4 楼 zhao4zhong1 的回复:
仅供参考:
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <share.h>
#include <conio.h>
int fh;
int c,r;
__int64 offset,offset1,i64,n64,l64,r64;
char ln[16000+1];
int main(int argc,char **argv) {
    if (argc<2) {
        fprintf(stderr,"Usage:%s filename.txt [10]\nto reverse lines of file [default the last 10 lines,-1 for all lines].\n",argv[0]);
        return 1;
    }
    if (argc==2) n64=10i64;
    if (argc>2) sscanf(argv[2],"%I64d",&n64);
    fh=_sopen(argv[1],_O_BINARY|_O_RDONLY|_O_RANDOM,_SH_DENYNO);
    if (-1==fh) {
        fprintf(stderr,"Can not _sopen file %s!\n",argv[1]);
        return 2;
    }
    l64=_filelengthi64(fh);if (l64==0i64) {_close(fh);return 0;}
    offset=l64;
    offset1=_lseeki64(fh,-1i64,SEEK_END);
    if (offset1==-1i64) {_close(fh);return 3;}
    i64=0i64;
    while (1) {
        if (_read(fh,&c,1)<1) break;//
        if (('\n'==c && offset1<l64-1i64) || offset1==0i64) {
            if (offset1!=0i64) offset1++;
            if (_lseeki64(fh,offset1,SEEK_SET)==-1i64) break;//
            r64=offset-offset1;
            if (r64<=16000i64) {
                r=_read(fh,ln,(unsigned int)r64);
                if (r<=0) break;//
            } else {
                r=16000;
                while (1) {
                    if (r64>(__int64)r) {
                        r64-=(__int64)r;
                        if (1i64==r64 || 2i64==r64) {
                            r=8000;
                            r64+=(__int64)r;
                        }
                    } else {
                        r=(int)r64;
                        r64=0i64;
                    }
                    r=_read(fh,ln,r);
                    if (r<=0) break;//
                    if (0i64==r64) break;//
                    ln[r]=0;
                    printf("%s",ln);
                    r=16000;
                }
                if (r<=0) break;//
            }
            ln[r]=0;
            if (r>=2 && ln[r-1]=='\n' && ln[r-2]=='\r') {ln[r-2]='\n';ln[r-1]=0;r--;}//避免输出重定向到文件时行尾多出'\r'
            if (i64==0I64) {
                if ('\n'!=ln[r-1]) printf("%s\n",ln);
                else               printf("%s",ln);
            } else {
                printf("%s",ln);
            }
            i64++;
            if ((i64%10000)==0) cprintf("\r%I64d/%I64d",offset1,l64);
            if (n64>0i64 && i64>=n64) break;//
            offset=offset1;
            _lseeki64(fh,offset1-2i64,SEEK_SET);
            offset1-=2i64;
        } else {
            _lseeki64(fh,-2i64,SEEK_CUR);
            offset1--;
        }
    }
    _close(fh);
    return 0;
}
我才疏学浅,怎么没看懂您的代码呢?? 请问您的思想是什么,我可以自己写代码哒 谢谢啦!!
Lawake 2013-08-31
  • 打赏
  • 举报
回复
引用 5 楼 ananluowei 的回复:
[quote=引用 1 楼 damingg 的回复:] 每行的字节数固定么? 如果是的,那么可以试试seek
+1 如果每行数字不对齐,或者说每行的长度不一致,只能从头一行行读,自己计数。[/quote] 嗯,我想过这个方法,但是数据量太大了,131G,我每行都要处理,那么处理到最后一行的时候还是相当与把所有数据都读进去了,肯定是不行的~~~~
Lawake 2013-08-31
  • 打赏
  • 举报
回复
引用 楼主 Lawake 的回复:
文件中都是正整数,共20万行,1235列,131G 都是0-255之间的整数。 我每次想提取某一行 在网上都是把文件全部读进内存后再取某一行,但是不适用于这种大数据的情况。 不知道大家有没有什么好方法呢?请帮助,谢谢!!!
不固定,所以没办法用seek函数 愁~~
大尾巴猫 2013-08-30
  • 打赏
  • 举报
回复
引用 1 楼 damingg 的回复:
每行的字节数固定么? 如果是的,那么可以试试seek
+1 如果每行数字不对齐,或者说每行的长度不一致,只能从头一行行读,自己计数。
赵4老师 2013-08-30
  • 打赏
  • 举报
回复
仅供参考:
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <share.h>
#include <conio.h>
int fh;
int c,r;
__int64 offset,offset1,i64,n64,l64,r64;
char ln[16000+1];
int main(int argc,char **argv) {
    if (argc<2) {
        fprintf(stderr,"Usage:%s filename.txt [10]\nto reverse lines of file [default the last 10 lines,-1 for all lines].\n",argv[0]);
        return 1;
    }
    if (argc==2) n64=10i64;
    if (argc>2) sscanf(argv[2],"%I64d",&n64);
    fh=_sopen(argv[1],_O_BINARY|_O_RDONLY|_O_RANDOM,_SH_DENYNO);
    if (-1==fh) {
        fprintf(stderr,"Can not _sopen file %s!\n",argv[1]);
        return 2;
    }
    l64=_filelengthi64(fh);if (l64==0i64) {_close(fh);return 0;}
    offset=l64;
    offset1=_lseeki64(fh,-1i64,SEEK_END);
    if (offset1==-1i64) {_close(fh);return 3;}
    i64=0i64;
    while (1) {
        if (_read(fh,&c,1)<1) break;//
        if (('\n'==c && offset1<l64-1i64) || offset1==0i64) {
            if (offset1!=0i64) offset1++;
            if (_lseeki64(fh,offset1,SEEK_SET)==-1i64) break;//
            r64=offset-offset1;
            if (r64<=16000i64) {
                r=_read(fh,ln,(unsigned int)r64);
                if (r<=0) break;//
            } else {
                r=16000;
                while (1) {
                    if (r64>(__int64)r) {
                        r64-=(__int64)r;
                        if (1i64==r64 || 2i64==r64) {
                            r=8000;
                            r64+=(__int64)r;
                        }
                    } else {
                        r=(int)r64;
                        r64=0i64;
                    }
                    r=_read(fh,ln,r);
                    if (r<=0) break;//
                    if (0i64==r64) break;//
                    ln[r]=0;
                    printf("%s",ln);
                    r=16000;
                }
                if (r<=0) break;//
            }
            ln[r]=0;
            if (r>=2 && ln[r-1]=='\n' && ln[r-2]=='\r') {ln[r-2]='\n';ln[r-1]=0;r--;}//避免输出重定向到文件时行尾多出'\r'
            if (i64==0I64) {
                if ('\n'!=ln[r-1]) printf("%s\n",ln);
                else               printf("%s",ln);
            } else {
                printf("%s",ln);
            }
            i64++;
            if ((i64%10000)==0) cprintf("\r%I64d/%I64d",offset1,l64);
            if (n64>0i64 && i64>=n64) break;//
            offset=offset1;
            _lseeki64(fh,offset1-2i64,SEEK_SET);
            offset1-=2i64;
        } else {
            _lseeki64(fh,-2i64,SEEK_CUR);
            offset1--;
        }
    }
    _close(fh);
    return 0;
}
孤影品茗 2013-08-30
  • 打赏
  • 举报
回复
C语言有系统提供的fread和fwrite,FILE类型的文件内部有个指针p(具体名字忘了,用p代替),用来指示当前读取到的文件的位置,程序一般都不太可能都将文件读取到内存然后处理,因为这样明显不可能处理大文件,你可以用ftell来对文件的p指针进行重定位,这样就可以处理了,尤其是文件格式整齐的,处理起来很方便。
赵4老师 2013-08-30
  • 打赏
  • 举报
回复
仅供参考:
//问题:
// 1.打开一个文本文件。
// 2.查找这个文本文件的第r行的第c1-c2列?
//
// 如:
// 文件:a
// 11111111
// 22222QQQ
// 33333333
//
// 查找第2行,第6-8列。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXC 16000
char ln[MAXC];
FILE *f;
int r,c1,c2,n,L;
void getc1c2(char *fn) {
    ln[c2]=0;
    printf("Text at row(%d),column(%d..%d) of file %s is [%s]\n",r,c1,c2,fn,ln+c1-1);
}
int main(int argc,char **argv) {
    if (argc<5) {
    HELP:
        printf("Usage:\n    %s filename.ext r c1 c2\nto get text at row(r),column(c1..c2) of filename.ext\n",argv[0]);
        return 1;
    }
    r=atoi(argv[2]);
    c1=atoi(argv[3]);
    c2=atoi(argv[4]);
    if (r<=0 || c1<=0 || c2<c1 || c2>=MAXC) goto HELP;
    f=fopen(argv[1],"r");
    if (NULL==f) {
        printf("Can not open file %s!\n",argv[1]);
        return 2;
    }
    n=0;
    while (1) {
        if (NULL==fgets(ln,MAXC,f)) break;
        L=strlen(ln);
        if ('\n'==ln[L-1]) {
            memset(ln+L-1,0,MAXC-L+1);
            n++;
            if (r==n) {getc1c2(argv[1]);break;}
        } else {
            n++;
            if (r==n) {getc1c2(argv[1]);break;}
            printf("Warning: line %d too long(>%d characters)! Ignore tails.",n,MAXC);
            while (1) {
                if (NULL==fgets(ln,MAXC,f)) goto END;
                L=strlen(ln);
                if ('\n'==ln[L-1]) break;
            }
        }
    }
    END:
    fclose(f);
    return 0;
}
//C:\test\Debug>frcc a 2 6 8
//Text at row(2),column(6..8) of file a is [QQQ]
//
damingg 2013-08-30
  • 打赏
  • 举报
回复
每行的字节数固定么? 如果是的,那么可以试试seek

64,631

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧