急求:有关c语言对文件中指定数据删除的问题,谁能帮我解答一下啊?
要求对文本文件里面某段指定的内容进行删除,而且里面的内容很多,文件很大,有50多M,每段内容的形式都是一样的,如:1,tcp,ftp,SF,856,2586,0,0,0,18,0,1,0,0,0,0,0,0,0,0,0,1,1,1,0.00,0.00,0.00,0.00,1.00,0.00,0.00,221,44,0.20,0.03,0.00,0.00,0.00,0.00,0.00,0.00,normal
要求对其中一段内容进行删除,比如上面这行的内容。
我现在想到的解决方法是,把除了这段的其他内容复制到新的文件内,再复制回来,可是因为文件很大,应该会花很多的时间。另外一种想法是,把后面的字符一个一个前移覆盖,最后将整行数据覆盖,可是不知道怎么处理。另外一种想法是,把最后一行的数据覆盖这段数据,但是不知道有没有整行覆盖的命令,而且覆盖完了也不知道怎样删除。
我之前是用结构体存放这些数据的,类似这样,
struct genes{
int duration;
char p_type[5]; // protocol_type
char service[15];
char flag[4];
unsigned long src_bytes;
unsigned long dst_bytes;
int land;
int wrong_f; // wrong_fragment
int urgent;
int hot;
int num_fl; // num_failed_logins
int logged_in;
int num_com; // num_compromised
int root_shell;
int su_attemp; // su_attempted
int num_root;
int num_fc; // num_file_creations
int num_shells;
int num_af; // num_access_files
int num_oc; // num_outbound_cmds
int ih_login; // is_host_login
int ig_login; // is_guest_login
int count;
int srv_c; // srv_count
float serror_r; // serror_rate
float ss_r; // srv_serror_rate
float rerror_r; // rerror_rate
float sr_r; // srv_rerror_rate
float ssrv_r; // same_srv_rate
float dsrv_r; // diff_srv_rate
float sdh_r; // srv_diff_host_rate
int dsth_c; // dst_host_count
int dsths_c; // dst_host_srv_count
float dhsas_r; // dst_host_same_srv_rate
float dhds_r; // dst_host_diff_srv_rate
float dhssp_r; // dst_host_same_src_port_rate
float dhsdh_r; // dst_host_srv_diff_host_rate
float dhs_r; // dst_host_serror_rate
float dhsse_r; // dst_host_srv_serror_rate
float dshr_r; // dst_host_rerror_rate
float dhsr_r; // dst_host_srv_rerror_rate
char label[20];
}data;
不知道问题解释清楚没有,希望哪位高手可以帮我看一下,真的很急,谢谢了!!
[解决办法]
文本覆盖、插入、修改,简单的示例一下:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp;
char *insert = "EE,EE,EE, ", tmp[256]={0};
int pos, i;
/*test.txt文件内容:01,00,00,00,0E,00,00,00,00,00,00,E1,E2,00,00,00,00*/
fp = fopen( "test.txt ", "r+ ");
/*1、等长覆盖*/
fseek(fp, 12, 1);
fprintf(fp, "0F "); /*直接写入等长度的数据就可以完成覆盖*/
/*2、E2后插入“EE,EE,EE,” */
fseek(fp, 25, 1);
pos = ftell(fp); /*插入位置*/
fgets(tmp, 256, fp); /*把后面的数据缓存*/
fseek(fp, pos, 0); /*移动到插入位置*/
fprintf(fp, insert); /*插入,就是写入数据*/
fprintf(fp, tmp); /*把原来的数据再写回来, 完成*/
/*3、01读取后++两次,并重新写回文件*/
rewind(fp);
fscanf(fp, "%x ", &i); /*读取数据*/
i = i+2; /* +2 */
fseek(fp, -2, 1); /*调整指针*/
fprintf(fp, "%02x ", i); /*写文件*/
fclose(fp);
system( "PAUSE ");
return 0;
}
[解决办法]
另外一种想法是,把最后一行的数据覆盖这段数据,但是不知道有没有整行覆盖的命令,而且覆盖完了也不知道怎样删除。
=============
如果没有 记录的顺序要求,
那么可以考虑使用这个方法。
1 搜索需要删除的记录,记录起始位置start。
2 读取末尾记录,并写入 start 位置,这样得到 等长覆盖,即用末尾记录覆盖了需要删除的记录。
3 文件截断:
int ftruncate(int fd,off_t length);. 函数说明. ftruncate()会将参数fd指定的文件大小改为参数length指定的大小。参数fd为已打开的文件描述词,而且必须是以写入模式打开的文件。如果原来的文件大小比参数length大,则超过的部分会被删去。
【参看 http://www.opengroup.org/onlinepubs/007908775/xsh/ftruncate.html】
或者 是chsize:
函数名: chsize
功 能: 改变文件大小
用 法: int chsize(int handle, long size);
程序例:
#include <string.h>
#include <fcntl.h>
#include <io.h>
int main(void)
{
int handle;
char buf[11] = "0123456789 ";
/* create text file containing 10 bytes */
handle = open( "DUMMY.FIL ", O_CREAT);
write(handle, buf, strlen(buf));
/* truncate the file to 5 bytes in size */
chsize(handle, 5);
/* close the file */
close(handle);
return 0;
}
[解决办法]
另外一种想法是,把最后一行的数据覆盖这段数据,但是不知道有没有整行覆盖的命令,而且覆盖完了也不知道怎样删除。
------------
如果记录不需要排序,这个方法是比较好的
前提是你的每行记录长度一样,有一字节的差别都不行
至于怎么覆盖用ftell fseek fwrite 就ok了
[解决办法]
楼主说每段的形式一样,不知是否等长。如果等长则用最后一段覆盖当前段,然后用chsize改变文件长度。如果不是等长则需要将其它段写入新文件然后删除此文件并将新文件重新命名。
[解决办法]
不太明白楼主需求,要删除的时候应该是满足某一条件的那一行被删除巴,那条件是什么呢?假设使用这句话中的关键字,就是最后一个变量label,你可以用一个map来存放这个struct,然后map的key用这个label,然后循环读取该map,将满足条件的记录跳过不读,其他的村到另一个map中,不就行了吗?map是个很好的stl,要学会利用它,效率还是蛮高的,针对你的需求,你也可以用vector来实现,毕竟你是顺序读取,不是靠关键字来找的
[解决办法]
我认为给每条记录添加一个删除标记是个很好的办法(楼上的一些朋友已经提到),这样同时可以实现一个逻辑删除的功能,即随时可以恢复。然后再提供一个压缩功能,执行时重新整理,正式丢弃那些标志为删除的空间,使整个数据文件连续且紧凑。这样做的好处很明显:删除是很经常的操作,随时都有可能发生,应该保证其具备一定的效率。压缩可以由用户选择,在某个空闲时间进行,给了用户很大的灵活性。
还有一个办法就是和内存分配算法一样,把删除的空间连成一个空闲表,下次写记录的时候先从空闲表里找最合适的空间。当然这要求记录的存放可以是不连续的。如果要求记录顺序也可以给记录加标号,或者把记录连成链表。
另有一种更好但是更复杂的方法,就是分块存储,数据库系统常用的存储机制。例如 4K 或 8K 一个块,或者按软件的实际需要选择一个块尺寸。块形成链表,块内的数据保持紧凑,即接连存放,没有碎片,每个块内都可能会存在一点多余的空间。每次删除时仅移动块内的记录,由某种策略决定块的合并和删除。这种方法的好处是保证高频度的任意长数据的插入和删除拥有一定的效率,但复杂性不言而喻,看楼主的需求可能还是选择一个更简单的方案更合适。