2012-04-09 32 views
3

UnixからWindowsに変換するとき、正しい出力が得られます。しかし、WindowsからUnixに移行するとき、私はいくつかの奇妙な出力を得ます。私はキャリッジリターン、 '\ r'の除去が許されなければならないと思った。これはうまくいかない。コードを実行した後にテキストファイルを開くと、奇妙な結果が得られます。最初の行は正しいので、すべての地獄ブレークは失われます。WindowsからUnixにテキストファイルを変換する方法

int main() 
{ 
    bool windows = false; 
    char source[256]; 
    char destination[256]; // Allocate the max amount of space for the filenames. 

    cout << "Please enter the name of the source file: "; 
    cin >> source; 

    ifstream fin(source, ios::binary); 
    if (!fin)   // Check to make sure the source file exists. 
    { 
     cerr << "File " << source << " not found!"; 
     getch(); 
     return 1; 
    }//endif 

    cout << "Please enter the name of the destination file: "; 
    cin >> destination; 

    ifstream fest(destination); 
    if (fest)   // Check to see if the destination file already exists. 
    { 
     cout << "The file " << destination << " already exists!" << endl; 
     cout << "If you would like to truncate the data, please enter 'Y', " 
      << "otherwise enter 'N' to quit: "; 
     char answer = char(getch()); 
     if (answer == 'n' || answer == 'N') 
     { 
     return 1; 
     }//endif 
    }//endif 
    clrscr();   // Clear screen for neatness. 

    ofstream fout(destination, ios::binary); 
    if (!fout.good()) // Check to see if the destination file can be edited. 
    { 
     cout << destination << "could not be opened!" << endl; 
     getch(); 
     return 1; 
    }//endif 
         // Open the destination file in binary mode. 
    fout.open(destination, ios::binary); 
    char ch = fin.get(); // Set ch to the first char in the source file. 
    while (!fin.eof()) 
    { 
     if (ch == '\x0D') // If ch is a carriage return, then the source file 
     {     // must be in a windows format. 
     windows = true; 
     }//endif 
     if (windows == true) 
     { 
     ch = fin.get(); // Advance ch, so that at the bottom of the loop, the 
     }//endif   // carriage return is not coppied into the new file. 
     if (windows == false) 
     { 
     if (ch == '\x0A') // If the file is in the Unix format.. 
     { 
      fout.put('\x0D'); // When a new line is found, output a carriage 
     }//endif    // return. 
     }//endif 

     fout.put(ch); 
     ch = fin.get(); 
    }//endwh 
    if (windows == true) 
    { 
     fout.put('\x0A'); 
    }//endif 
    fout.close(); 
    fin.close();     // Close yer files. 

    if (windows == true)  // A little output for user-friendly-ness. 
    { 
     cout << "The contents of " << source << " have been coppied to " 
      << destination << " and converted to Unix format." << endl; 
    }else{ 
     cout << "The contents of " << source << " have been coppied to " 
      << destination << " and converted to Windows format." << endl; 
    }//endif 
    cout << "Enter any key to quit.." << endl; 
    getch(); 
    return 0; 
}//endmn 
+0

だから、どうしたらいいですか? –

+0

スクリプトを使用できる場合は、linux/unixプラットフォームでdos2unixを使用することもできます。 – weima

+1

この場合はあなたの問題だとは思えませんが、本当に 'fest 'を呼び出すべきです。close() 'を実行して宛先ファイルの入力ストリームを閉じてから出力ストリームとして開くこともできます。 –

答えて

4

は、*(十分なあなたのための改行を処理しますこの場合はメンバーでないgetline()を使って行を出力し、\ nまたは\ r \ nを最後の行を除く各行の後に挿入して出力ファイルに出力します。

その後、元のファイルを削除し、元のファイルの名前になるように一時ファイルの名前を変更することができます。または、必要に応じて、行をベクター<の文字列>にpush_backすることができます。次に、ファイルへの入力ハンドルを閉じ、outstream( "filename"、ios_base :: trunc)を実行して、ベクトルの要素をファイルに書き込んで、必要な改行で区切ります。

これはすべて要件に応じて異なります。

以下は、エラー処理が最小限である例です。しかし、これは実際にはFORループと、行ごとに読んで、私がここで別のやり方で示したかったものです。

convert_file.exe "test.txtの" の "Linux"

convert_file.exe "test.txtの"

#include <iostream> 
#include <string> 
#include <fstream> 
#include <ostream> 
#include <cstdlib> 
#include <cstdio> 
using namespace std; 

int main(int argc, char* argv[]) { 
    if (argc != 3) { 
     cerr << "Usage: this.exe file_to_convert newline_format(\"linux\" or \"win\")" << endl; 
     return EXIT_FAILURE; 
    } 
    string fmt(argv[2]); 
    if (fmt != "linux" && fmt != "win") { 
     cerr << "Invalid newline format specified" << endl; 
     return EXIT_FAILURE; 
    } 
    ifstream in(argv[1]); 
    if (!in) { 
     cerr << "Error reading test.txt" << endl; 
     return EXIT_FAILURE; 
    } 
    string tmp(argv[1]); 
    tmp += "converted"; 
    ofstream out(tmp.c_str(), ios_base::binary); 
    if (!out) { 
     cerr << "Error writing " << tmp << endl; 
     return EXIT_FAILURE; 
    } 
    bool first = true; 
    for (string line; getline(in, line);) { 
     if (!first) { 
      if (fmt == "linux") { 
       out << "\n"; 
      } else { 
       out << "\r\n"; 
      } 
     } 
     out << line; 
     first = false; 
    } 
    in.close(); 
    out.close(); 
    if (remove(argv[1]) != 0) { 
     cerr << "Error deleting " << argv[1] << endl; 
     return EXIT_FAILURE; 
    } 
    if (rename(tmp.c_str(), argv[1]) != 0) { 
     cerr << "Error renaming " << tmp << " to " << argv[1] << endl; 
     return EXIT_FAILURE; 
    } 
} 

が他の人がユーティリティが既に存在している、しかし言ったように "勝つ"(含むテキストあなたのために改行を行うNotepadd ++のようなエディタ)したがって、あなたが他の理由でこれをしている場合を除いて、自分で何も実装する必要はありません(指定していません)。

+0

自分のロジックやアルゴリズムに何か問題があったかどうかを知りたかったと思います。 – Jerrod

1

あなたは適切なフォーマットでデータを読み込み、右の形式で保存していることを確認しましたか?

別の文字エンコーディングで動作させようとしていて、それを「読み込む」だけでは非常に悪いことが起こります。

また、実行する必要のある別の代替品についても考慮する必要があります。

これはlink

+0

私のC++知識はかなり限られています。私はバイナリコードでデータを読んでいるので、そのレベルではWindowsとUnix間のフォーマットに違いはありません。したがって、私が知る限り、Windowsの改行文字は "/ r/n"と読み替えられ、Unixは "/ n"と読み込まれます。したがって、3つの異なる行にある3つの単語を持つUnixテキストファイルは、ウィンドウ内で開かれると、1行に3つの単語として表示されます。これは、ウィンドウの前に "/ r"を付けずに改行として "/ n"を認識しないためです。だから私には、 "/ r"を追加するだけです。それが私が試みたものです。 – Jerrod

+0

はい、ファイルがUTF-16としてエンコードされている場合は、 '\ r \ 0 \ n \ 0'を' \ n \ 0'に置き換える必要があります。そのようなもの。 –

2

私は再編集し、あなたのコードを持って、それは私のために正常に動作します。..

希望を助けるかもしれない、このことができます!

#include <iostream> 
#include <fstream> 
#include <iostream> 
#include<stdio.h> 
using namespace std; 

int main() 
{ 
    bool windows = false; 
    char source[256]; 
    char destination[256]; // Allocate the max amount of space for the filenames. 

    cout << "Please enter the name of the source file: "; 
    cin >> source; 

    ifstream fin(source, ios::binary); 
    if (!fin)   // Check to make sure the source file exists. 
    { 
     cerr << "File " << source << " not found!"; 
     return 1; 
    }//endif 

    cout << "Please enter the name of the destination file: "; 
    cin >> destination; 

    ifstream fest(destination); 
    if (fest)   // Check to see if the destination file already exists. 
    { 
     cout << "The file " << destination << " already exists!" << endl; 
     cout << "If you would like to truncate the data, please enter 'Y', " 
     << "otherwise enter 'N' to quit: "; 
     char answer; 
     cin >> answer; 
     if (answer == 'n' || answer == 'N') 
     { 
      return 1; 
     } 
    } 
    //clrscr(); 

    ofstream fout(destination); 
    if (!fout.good()) 
    { 
     cout << destination << "could not be opened!" << endl; 
     return 1; 
    } 
    char ch = fin.get(); 
    while (!fin.eof()) 
    { 
     if (ch == '\r') 
     {     
      windows = true; 
     } 
     if (ch == '\n' && windows == false) // If the file is in the Unix format.. 
     { 
      // Don't do anything here 
     } 
     fout.put(ch); 
     cout << ch; // For Debugging purpose 
     ch = fin.get(); 
    } 
    fout.close(); 
    fin.close(); 

    if (windows == true)  // A little output for user-friendly-ness. 
    { 
     cout<<endl; 
     cout << "The contents of " << source << " have been coppied to " 
     << destination << " and converted to Unix format." << endl; 
    }else{ 
     cout << "The contents of " << source << " have been coppied to " 
     << destination << " and converted to Windows format." << endl; 
    }//endif 
    cout << "Enter any key to quit.." << endl; 
    return 0; 
} 
+1

これは、ファイルを別のファイルにコピーする以外は何もしないようです。フォーマットは、一方向または他の方法で正常に変換されません。 – Jerrod

2

ループ内のウィンドウを確認する心配はありません。キャリッジリターンを確認するだけです。変数 'c​​arriage_return'を設定します。次の繰り返しは、 'carriage-return'とch!= linefeedの場合は、改行を挿入するだけです。次に、carriage_return変数をfalseにリセットします。それはあなたを間違って送り込まない、とてもシンプルで基本的なルールです。あなただけの単純なASCII(そしておそらくUTF-8)テキストファイルを変換する必要がある*、あなたが翻訳モードでループ内でライン・バイ・ラインをソースファイルを読み込むことができれば

bool carriage_return = false; 
const char linefeed = '\n'; // Is it? I forget. 
const char cr = '\r'; // I forget again. Too late to check. 
char ch = fin.get(); 
if (ch == cr) carriage_return = true; 
while (!fin.eof()){ 
    if (carriage_return) { // Check if we already have a newline 
    if (ch != linefeed) { // If we have a newline previously, we need a linefeed. If it's already there just leave it, if it isn't there put it in 
     fout.put(linefeed); 
    } 
    if (ch != cr) carriage_return = false; // Reset the carriage-return flag *if* we don't have another carriage return. This handles multiple empty lines in an easy way for us. 
    } 

    fout.put(ch); 
    ch = fin.get(); 
} 
+0

LFが '\ n'で、CRが' \ r'であることは間違いありません。 –

関連する問題