【问题标题】:Writing a C++ program that can merge files from the command line in Linux在 Linux 中编写一个可以从命令行合并文件的 C++ 程序
【发布时间】:2014-09-23 02:24:07
【问题描述】:

我编写了一个 C++ 程序,它应该打开两个文本文件(prog2a.datprog2b.dat)并写入指定范围的行的内容到输出文件 (outfile.dat)。我编写了一个基于我们给出的示例的程序(从第一个文件中获取行 5-15 和第二个文件的行 4-12 并将它们合并到输出文件中)完美地工作。然而,在要求我的教授对作业的另一部分进行澄清后,我发现我没有正确地做到这一点。我编写了代码,以便它始终输出我前面提到的行范围,但该程序实际上应该允许用户通过键入以下命令使用他们想要的任何范围从命令行合并文件:

prog2 in1 5-15 in2 4-12 outfile

但我不确定如何调整我当前的程序以允许这样做。

这是我编写的代码,请记住,这适用于它的编写方式,但不适用于命令行的目的(希望这是有道理的):

#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;

int main() {
    // Create output file
    std::ofstream outFile("outfile.dat", ios::out);

    // Open input file 1, if can't be opened, exit
    ifstream in1;
    in1.open("prog2a.dat");
    std::string line;
    int count = 1;
    if (!in1) {
        cerr << "Open Failure" << endl;
        exit(1);
    } // end if
    else {
        while (std::getline(in1, line)) {
            if (count >= 5 && count <= 15) {
                outFile << line << "\n"; /*writes the contents of
                lines 5-15 to outfile.dat*/
            }
            ++count;
        } // end while
    } // end else
    in1.close(); // close in1 (prog2a.dat)
    outFile << "\n"; // add a blank line after the output from prog2a.dat
    count = 1; // reset the line count to 1 before opening next file.

    // Open input file 2, if can't be opened, exit
    ifstream in2;
    in2.open("prog2b.dat");
    if (!in2) {
        cerr << "Open Failure" << endl;
        exit(1);
    } // end if
    else {
        while (std::getline(in2, line)) {
            if (count >= 4 && count <= 12) {
                outFile << line << "\n"; /*writes the contents of the
                lines 4-12 to outfile*/
            }
            ++count;
        } // end while
    } // end else
    in2.close(); // close in2 (prog2b.dat)
} // end main

是否有任何简单的方法可以像我使用命令行描述的那样完成这项工作?另外,我应该把它分成三个文件,一个头文件,程序文件和一个测试文件(测试文件包含main(),应该关闭3个打开的文件并显示任何错误消息),但我'我对头文件中应该包含的内容感到非常困惑。我知道头文件应该包含类定义和构造函数,但真的不知道如何使它适用于这个特定的程序?我对此非常陌生,因此将不胜感激任何指针。

【问题讨论】:

  • 这个程序真的可以编译吗? (class prog2 { int main()..})?
  • 是的,并且在输出文件中产生了正确的输出。
  • 类中不能有 main(),这不是 java。您的程序无法编译,只需复制/粘贴它并使用 g++ 尝试。
  • 啊,好吧,我运行后肯定添加了类。我会解决的,谢谢指出。就像我说的那样,我在这方面真的很陌生,并且正在学习。
  • 您应该声明int main(int argc, char**argv) 并使用它的参数。对于单个源程序,您不需要任何自己的 *.h 标头(但当然您需要 #include 几个标准标头)

标签: c++ linux file merge


【解决方案1】:

问题是行号和文件名在您的 main 函数中是硬编码的。如 cmets 中所述,您需要处理主函数参数。此外,您的代码包含可以轻松移动到单独函数的重复项(读取输入文件并将所需的字符串复制到输出)。我通过将相关代码移动到单独的函数中删除了一些重复项。还是需要检查错误:看看代码中的//TODOcmets:

#include <iostream>
#include <string>
#include <fstream>

using namespace std;


bool lineNumbersFromString(const std::string& aString, int& startPos, int& endPos)
{
    std::size_t pos = aString.find('-');

    if (pos < 0 || pos >= aString.length())
    {
        return false;
    }


    std::string start = aString.substr(0, pos);
    std::string end = aString.substr(pos + 1, aString.length()-1);

    if (start.length() == 0 || end.length() == 0)
    {
        return false;
    }

    startPos = atoi(start.c_str());
    endPos = atoi(end.c_str());

    return true;

}

bool copyLinesToOutFile(std::string& inputFileName, int startLine, int endLine, std::ofstream& outFileStream)
{
    ifstream inputFileStream;
    inputFileStream.open(inputFileName.c_str());

    if (!inputFileStream)
    {
        cerr << "Cannot open file: " << inputFileName << endl;
        return false;  
    } 

    int lineCount = 0;
    std::string line;
    while (std::getline(inputFileStream, line))
    {
        if (lineCount >= startLine && lineCount <= endLine)
        {
            outFileStream << line << "\n";
        }
        ++lineCount;
    }
    inputFileStream.close();
}

int main(int argc, char** argv)
{
    if (argc != 6)
    {
        //Invalid number of arguments
        //TODO: report error
        return -1;
    }

    std::string firstFileName = argv[1];
    std::string firstFileRange = argv[2];
    std::string secondFileName = argv[3];
    std::string secondFileRange = argv[4];
    std::string outFileName = argv[5];

    int firstStartPos = 0;
    int firstEndPos = 0;

    bool ok = false;

    ok = lineNumbersFromString(firstFileRange, firstStartPos, firstEndPos);
    //TODO: check error

    // Create output file
    std::ofstream outFile(outFileName.c_str(), ios::out);

    ok = copyLinesToOutFile(firstFileName, firstStartPos, firstEndPos, outFile);
    //TODO: check error

    int secondStartPos = 0;
    int secondEndPos = 0;
    ok = lineNumbersFromString(secondFileRange, secondStartPos, secondEndPos);
    //TODO: check error

    ok = copyLinesToOutFile(secondFileName, secondStartPos, secondEndPos, outFile);
    //TODO: check error

    outFile.close();

    return 0;
}

附:希望这可以帮助。将其拆分为单独的文件应该不是什么大问题。

【讨论】:

  • 顺便说一句,代码不会检查输入文件的行号是否有效以及输入文件是否足够长。您可能还想添加此逻辑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-02
  • 2018-07-07
  • 1970-01-01
  • 2011-03-29
  • 1970-01-01
  • 2016-06-28
  • 2014-09-08
相关资源
最近更新 更多