C语言删除TXT文本文件最后一行

思路分析

目的

希望能将给定txt文件的最后一行(无论是空行还是第一行)删掉,并直接保存,而不是另存为某个新的txt文件。

例1:

原文件:
1234567
abcdefg
处理后:
1234567

例2:

原文件:
Hello World!

处理后:
Hello World!

例3:

原文件:
This is an example.
处理后

算法流程

大体思路如下:

  1. 以只读方式打开原文件。
  2. 以只写方式打开一个临时文件。
  3. 通过从原文件末尾向前查找换行符的方式确定最后一行的位置
  4. 从原文件开头逐个读取字符,写入临时文件,直到第3步中确定的位置
  5. 关闭文件,保存。
  6. 将原文件删除,将临时文件重命名为原文件的名称。

注:本文只用C语言实现,没有C++的内容。

几个需要注意的点

所用的函数

基本上就这几个:

errno_t __cdecl fopen_s(FILE **_Stream, const char *_FileName, const char *_Mode)
int __cdecl fseek(FILE *_Stream, long _Offset, int _Origin)
  • fgetc& fputc& fclose& ftell
  • remove& rename

具体用法看后面的源码吧,都不难,这里提供一个C++的帮助文档:cplusplus,大部分时候都挺好用的,所有函数都有例程,还可以在线跑例程。

二进制模式与文本模式

在使用fopen_s打开文件时,可以在第三个参数_Mode中添加字符b来开启二进制模式,否则为文本模式。

例如,fopen_s(&oldFile, txtFilePath, "rb")就是开启了二进制模式。

这两者的区别几乎只在于换行符,在本人的编程环境 Win10 Visual Studio 2019 (v142) 下:

  • 二进制模式读取的换行符为2个字符\r\n;而文本模式为2个字符\n\n
  • 二进制模式写入\n再读取为\n;而文本模式写入\n再读取为\r\n,即文本模式将\n填补为了完整的换行符

可以这么理解:

  • 二进制模式下,写入、读取和实际存储的数据,一定相同
  • 文本模式下,写入、读取和实际存储的数据,不一定相同

fseek的坑

fseek的第三个参数_Origin有以下三个选择:

常量代表的参考位置
SEEK_SET文件开头
SEEK_CUR文件指针的当前位置
SEEK_END文件末尾

(第二个参数_Offset代表相对于参考位置的偏移量,在此不展开赘述)

有趣的事情来了,使用SEEK_SET或者SEEK_END结合适当的偏移量都可以让文件指针换行,但SEEK_CUR无论偏移多少都无法让文件指针换行,十分地不明所以。

源码

Talk is cheap. Show me the code.

#include <stdio.h>
#include <string.h>

int main()
{
	//初始化变量
	FILE* oldFile;
	FILE* newFile;
	char txtFilePath[] = "data.txt";
	char tmpFilePath[] = "data_tmp.txt";

	//用"r"方式打开文件进行读取,"w"方式打开文件进行写入
	//使用二进制模式而不是文本模式打开文件(后面加了"b"),是为了处理起来更准确
	//二进制模式可以保证写入什么字符,就是什么字符,主要是在换行符上有作用
	//二进制模式下如果写入"\n",就是1个字符"\n",而文本模式下会自动填充成2个字符"\r\n"
	if (fopen_s(&oldFile, txtFilePath, "rb") || fopen_s(&newFile, tmpFilePath, "wb")) {
		printf("Error while opening file. \n");
		return 1;
	}

	char buffer = 0; //存储读取的字符
	//从文件末尾开始向前寻找"\n"换行符,并记录位置
	int curPos = 1; //当前光标位置
	while (true) {
		fseek(oldFile, -curPos, SEEK_END); //移动光标到文件倒数第curPos个字符前
		if (ftell(oldFile) == 0) {
			//若没有查找到,且光标已经位于文件开头,说明文件只有一行,则退出循环,删除该行
			break;
		}
		buffer = fgetc(oldFile); //读取字符到buffer
		//printf("%c", buffer); //输出查看
		if (buffer == '\n') {//注:C++中,双引号""表示字符串,单引号''表示字符,字符与字符串不能进行比较运算
			//换行符在二进制模式下为2个字符"\r\n",在文本模式下为2个字符"\n\n"
			//若查找到了,说明光标处于"\r"和"\n"之间,将光标再前移1次
			fseek(oldFile, -curPos - 1, SEEK_END); //将光标定位在倒数第二行的换行符前
			//退出循环,删除该换行符及之后的内容
			break;
		}
		else {
			//若没有查找到,则继续向前查找
			curPos++;
		}
	}
	int endPos = ftell(oldFile); //记录该光标位置

	//将从文件开头到endPos的内容复制到临时文件中
	fseek(oldFile, 0, SEEK_SET); //当前光标回到文件开头
	while (true) {
		curPos = ftell(oldFile);
		if (curPos == endPos) {
			break;
		}
		buffer = fgetc(oldFile); //读取字符到buffer
		fputc(buffer, newFile);
	}

	//关闭文件,保存
	fclose(oldFile);
	fclose(newFile);

	//删除旧文件,将临时文件名称改为旧文件名称,得到新文件
	remove(txtFilePath);
	if (rename(tmpFilePath, txtFilePath)) {
		printf("Error while renaming file. \n");
		return 2;
	}

	//结束
	printf("Successful. \n");
	return 0;
}

结语

很久没写C了,其实C++会的也不多……一直都是纯C写得多一点。

C给人的感觉就是一切都尽在掌握,自己会对代码的一举一动了如指掌,以及无比地僵硬(其实我还挺喜欢这种感觉的)。

网上的代码千奇百怪,还是要自己动手,才能写出简洁高效的代码!

  • 7
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言中,要让文本文件一行消失,可以通过以下步骤实现: 1. 打开文本文件:使用标准库函数fopen()来打开文本文件,指定打开方式为读取("r")或读取与写入("r+")。 2. 创建临时文件:使用标准库函数fopen()来创建一个新的临时文件,指定打开方式为写入("w")或读取与写入("w+")。 3. 处理文件内容:使用标准库函数fgetc()读取原始文件的字符。通过循环遍历每个字符,当遇到要消失的行时,跳过该行。 4. 写入数据到临时文件:使用标准库函数fputc()将处理后的字符写入新的临时文件。 5. 关闭文件:使用标准库函数fclose()关闭原始文件和临时文件。 6. 删除原始文件:使用标准库函数remove()删除原始文件。 7. 重命名临时文件:使用标准库函数rename()将临时文件重命名为原始文件的名称。 以下是一个示例代码,演示如何使用C语言文本文件一行消失: ```c #include <stdio.h> int main() { FILE *originalFile, *tempFile; originalFile = fopen("original.txt", "r"); // 打开原始文件 tempFile = fopen("temp.txt", "w"); // 创建临时文件 char c; while ((c = fgetc(originalFile)) != EOF) { if (c == '\n') { // 跳过要消失的行 while ((c = fgetc(originalFile)) != '\n') { continue; } } fputc(c, tempFile); // 将处理后的字符写入临时文件 } fclose(originalFile); // 关闭原始文件 fclose(tempFile); // 关闭临时文件 remove("original.txt"); // 删除原始文件 rename("temp.txt", "original.txt"); // 重命名临时文件 return 0; } ``` 以上代码会将名为"original.txt"的原始文件中的一行消失,并将处理后的文件重命名为"original.txt"。请注意,在使用这段代码之前,请备份原始文件以防止数据丢失。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值