How to convert a text file from Windows to Unix

c++

Solution

*If* you only need to convert simple ascii (and perhaps utf-8) text files, you could read the source file line-by-line in a loop in translated mode (handles newlines for you enough for this case) with non-member getline() and then output the lines to the output file while inserting \n or \r\n after each line except the last.

Then, you can remove the original file and rename the temp file to have the original file's name. Or, if you want, you can instead push_back the lines into a vector<string>. Then, you could close the input handle to the file, do ofstream out("filename", ios_base::trunc) and write the elements of the vector to the file while separating them by the newlines you want.

It all depends on your requirements.

The following is an example with minimal error handling. But, it's really only the FOR loop and reading line-by-line that I want to show here as a different way of doing things.

convert_file.exe "test.txt" "linux"

convert_file.exe "test.txt" "win"

#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;
    }
}

As others have said though, there are already utilities (including text editors like Notepadd++) that do newline conversion for you. So, you don't need to implement anything yourself unless you're doing this for other reasons (you didn't specify).

Problem

When converting from Unix to Windows, I get the correct output; however, when going from Windows to Unix I get some strange output. I thought all I had to allow for was the removal of the carriage return, '\r'. This isn't working though. When I open the text file after running the code, I get some strange results, the first line is correct, and then all hell breaks lose. ``` 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 ```

Original source