提问人:ubaabd 提问时间:6/11/2023 更新时间:6/11/2023 访问量:57
使用 C++ 将最后 $N $ 行打印到文件时出现“fseek”问题
`fseek` issue when printing last $N$ lines to a file using C++
问:
我正在使用以下代码将一个文件的最后一行打印到另一个文件。N
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
void printLastNLines(const std::string& inputFileName, const std::string& outputFileName, int N);
int main()
{
printLastNLines("test.csv", "test2.csv", 200);
}
void printLastNLines(const std::string& inputFileName, const std::string& outputFileName, int N) {
FILE* in, * out;
int count = 0;
long int pos;
char s[100];
fopen_s(&in, inputFileName.c_str(), "rb");
/* always check return of fopen */
if (in == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
fopen_s(&out, outputFileName.c_str(), "wb");
if (out == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
fseek(in, 0, SEEK_END);
pos = ftell(in);
while (pos) {
pos--;
fseek(in, pos, SEEK_SET);
char c = fgetc(in);
if (c == '\n') {
if (count++ == N) break;
}
}
//fseek(in, pos, SEEK_SET);
/* Write line by line, is faster than fputc for each char */
while (fgets(s, sizeof(s), in) != NULL) {
fprintf(out, "%s", s);
}
fclose(in);
fclose(out);
}
示例文件的内容如下:test.csv
2
3
但是,当我运行代码时,包含以下内容(不是说第一行在那里,但不包含任何字符:test2.csv
3
谁能指导代码出了什么问题?一般来说,当我给它一个更大的文件时,第一行的第一个字符总是丢失。
我以为这与文件指针位置有关。因此,我使用了另一行(目前已注释掉)和第一行开始打印。但是,我不确定为什么它需要这个额外的.当我调试代码时,执行的最后一行实际上是 .为什么我们需要额外的东西来让它工作?fseek(in, pos, SEEK_SET);
2
fseek
fseek(in, 0, SEEK_SET);
fseek(in, 0, SEEK_SET);
答:
0赞
Gurnet
6/11/2023
#1
该解决方案基本上已经在您的源代码中可见。但是你把它注释掉了://fseek(in, pos, SEEK_SET);
根本原因是你用来读取一个字符并将其与换行符进行比较。如果你找到一个 which read before,那么文件指针是 之后的一个。然后终止循环,文件指针位于错误的位置。getc
\n
\n
\n
因此,您可以取消注释您的陈述,但这也不可靠。根据您的操作系统,新行可能标有 ,因此回车符和换行符。对于您的系统来说,这很可能是正确的。然后搜索操作也不会做你所期望的。//fseek(in, pos, SEEK_SET);
\r\n
因此,没有简单的便携式解决方案。有一个快速修复,但不建议这样做。您可以尝试根据标记的行尾的专有技术来设置文件指针。
但是,如果您将 C++ 用于解决方案,那就更好了。
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std::string_literals;
void printLastNLines(const std::string& inputFileName, const std::string& outputFileName, int N) {
// Open files and check, if they could be opened
if (std::ifstream ifs(inputFileName); ifs)
if (std::ofstream ofs(outputFileName); ofs) {
// We will read all lines into a vector
std::vector<std::string> lines{};
for (std::string line{}; std::getline(ifs, line); lines.push_back(line));
// If N is greater then number of lines that we read, then limit the value
size_t numberOfLines = N < 0 ? 0 : N;
if (numberOfLines > lines.size()) numberOfLines = lines.size();
// And now we write the lines to the output file
for (size_t i = lines.size() - numberOfLines; i< lines.size(); ++i)
ofs << lines[i] << '\n';
}
else std::cout << "\nError: Coud not open input file '" << inputFileName << "'\n";
else std::cout << "\nError: Coud not open output file '" << outputFileName << "'\n";
}
int main() {
printLastNLines("r:\\test.csv"s, "r:\\test2.csv"s, 2);
}
评论
fgetc
将位置向前移动。fseek
std::queue
N
x