C++ 程序在 Linux 上正确打开文件,但在 Windows 上不正确
Posted
技术标签:
【中文标题】C++ 程序在 Linux 上正确打开文件,但在 Windows 上不正确【英文标题】:C++ program opens file corectly on Linux but not on Windows 【发布时间】:2014-09-06 01:04:18 【问题描述】:我通过 Mingw 在 Windows 上编译了一个 Linux 程序,但是输出错误。
错误说明: 该程序的输出在 Windows 上看起来与在 Linux 上不同。这是它在 Windows 上的外观:
>tig_2
CAATCTTCAGAGTCCAGAGTGGGAGGCACAGACTACAGAAAATGAGCAGCGGGGCTGGTA
>cluster_1001_conTTGGTGAAGAGAATTTGGACATGGATGAAGGCTTGGGCTTGACCATGCGAAGG
预期输出:
>cluster_1001_contig2
CAATCTTCAGAGTCCAGAGTGGGAGGCACAGACTACAGAAAATGAGCAGCGGGGCTGGTA
>cluster_1001_contig1
TTGGTGAAGAGAATTTGGACATGGATGAAGGCTTGGGCTTGACCATGCGAAGG
(注意:输出非常大,贴在这里,所以上面的例子是伪真实的)。
可能的原因: 我观察到,如果我将输入字符从 Linux (LF) 转换为 Windows (CRLF),它几乎可以工作:文件中的第一个字符 (>) 丢失。相同的代码在 Linux 上完美运行,无需任何输入转换。所以,问题一定出在解析输入的函数上,而不是写输出的函数上:
seq_db.Read( db_in.c_str(), options );
源代码: 这是解析输入文件的部分。无论如何,我可能错了。故障可能在其他地方。如果需要,完整的源代码是here :)
void SequenceDB::Read( const char *file, const Options & options )
Sequence one;
Sequence dummy;
Sequence des;
Sequence *last = NULL;
FILE *swap = NULL;
FILE *fin = fopen( file, "r" );
char *buffer = NULL;
char *res = NULL;
size_t swap_size = 0;
int option_l = options.min_length;
if( fin == NULL ) bomb_error( "Failed to open the database file" );
if( options.store_disk ) swap = OpenTempFile( temp_dir );
Clear();
dummy.swap = swap;
buffer = new char[ MAX_LINE_SIZE+1 ];
while (not feof( fin ) || one.size) /* do not break when the last sequence is not handled */
buffer[0] = '>';
if ( (res=fgets( buffer, MAX_LINE_SIZE, fin )) == NULL && one.size == 0) break;
if( buffer[0] == '+' )
int len = strlen( buffer );
int len2 = len;
while( len2 && buffer[len2-1] != '\n' )
if ( (res=fgets( buffer, MAX_LINE_SIZE, fin )) == NULL ) break;
len2 = strlen( buffer );
len += len2;
one.des_length2 = len;
dummy.des_length2 = len;
fseek( fin, one.size, SEEK_CUR );
else if (buffer[0] == '>' || buffer[0] == '@' || (res==NULL && one.size))
if ( one.size ) // write previous record
one.dat_length = dummy.dat_length = one.size;
if( one.identifier == NULL || one.Format() )
printf( "Warning: from file \"%s\",\n", file );
printf( "Discarding invalid sequence or sequence without identifier and description!\n\n" );
if( one.identifier ) printf( "%s\n", one.identifier );
printf( "%s\n", one.data );
one.size = 0;
one.index = dummy.index = sequences.size();
if( one.size > option_l )
if ( swap )
swap_size += one.size;
// so that size of file < MAX_BIN_SWAP about 2GB
if ( swap_size >= MAX_BIN_SWAP)
dummy.swap = swap = OpenTempFile( temp_dir );
swap_size = one.size;
dummy.size = one.size;
dummy.offset = ftell( swap );
dummy.des_length = one.des_length;
sequences.Append( new Sequence( dummy ) );
one.ConvertBases();
fwrite( one.data, 1, one.size, swap );
else
//printf( "==================\n" );
sequences.Append( new Sequence( one ) );
//printf( "------------------\n" );
//if( sequences.size() > 10 ) break;
//if( sequences.size() >= 10000 ) break;
one.size = 0;
one.des_length2 = 0;
int len = strlen( buffer );
int len2 = len;
des.size = 0;
des += buffer;
while( len2 && buffer[len2-1] != '\n' )
if ( (res=fgets( buffer, MAX_LINE_SIZE, fin )) == NULL ) break;
des += buffer;
len2 = strlen( buffer );
len += len2;
size_t offset = ftell( fin );
one.des_begin = dummy.des_begin = offset - len;
one.des_length = dummy.des_length = len;
int i = 0;
if( des.data[i] == '>' || des.data[i] == '@' || des.data[i] == '+' ) i += 1;
if( des.data[i] == ' ' or des.data[i] == '\t' ) i += 1;
if( options.des_len and options.des_len < des.size ) des.size = options.des_len;
while( i < des.size and ( des.data[i] != '\n') ) i += 1;
des.data[i] = 0;
one.identifier = dummy.identifier = des.data;
else
one += buffer;
#if 0
int i, n = 0;
for(i=0; i<sequences.size(); i++) n += sequences[i].bufsize + 4;
cout<<n<<"\t"<<sequences.capacity() * sizeof(Sequence)<<endl;
int i;
scanf( "%i", & i );
#endif
one.identifier = dummy.identifier = NULL;
delete[] buffer;
fclose( fin );
输入文件的格式是这样的:
> comment ACGTACGTACGTACGTACGTACGTACGTACGT > comment ACGTACGTACGTACGTACGTACGTACGTACGT > comment ACGTACGTACGTACGTACGTACGTACGTACGT etc
【问题讨论】:
尝试使用"rb"
打开。
"rb" 用于打开二进制文件。如果您不知道这意味着什么,那么这可能就是您遇到问题的原因。当您以“r”打开文件时,您允许运行时在您正在读取的数据中进行一些时髦的 CR/LF 转换,并且它不受您的控制。使用“rb”,没有翻译,构成文件的每个字符都按“原样”读取。
哦,另外,在您的代码中以“r”形式打开文件意味着Ctrl-Z
(ASCII 26)在 Windows 中标记了文件的结尾。因此,如果该文件包含 Ctrl-Z,则停止读取该文件。
'rb' 工作。请将其发布为答案,以便我接受。
@Altar - 使用“rb”导致该功能工作的原因是什么?是不是整个文件都没有被读取,而是在 Windows 的 Ctrl-Z 上停止了?
【参考方案1】:
问题很可能是您需要在对fopen
的调用中使用"rb"
开关打开文件。 "rb"
以二进制模式打开文件,而 "r"
以“文本”模式打开文件。
由于您在 Linux 和 Windows 之间来回切换,因此行尾字符会有所不同。如果您在 Windows 中将文件作为“文本”打开,但该文件是为 Linux 格式化的,那么您就是在向 Windows 撒谎,认为它是一个文本文件。所以运行时会做 CR/LF 转换都错了。
因此,您应该将文件作为二进制文件打开,"rb"
,这样就不会完成 CR/LF 转换。
【讨论】:
以上是关于C++ 程序在 Linux 上正确打开文件,但在 Windows 上不正确的主要内容,如果未能解决你的问题,请参考以下文章
C++ 程序在 Linux 上完美运行,但不能在 Windows 上运行