Im making a txt editor in the terminal, one of it's features is to edit a specific line.
To do so,
I am creating a new temporary txt file,
deleting the old/original one
and renaming the temporary one to the original.
Here's the code:
FileLineEdit(char filename[20], int line, char newline[1000]){
FILE * fp;
FILE * fptmp;
char buffer[1000];
int count;
int ret;
fp = fopen(filename, "r");
fptmp = fopen("tmp/replace.txt", "w");
if (fp == NULL || fptmp == NULL)
{
printf("\nErro!\n");
exit(1);
}
count = 0;
while ((fgets(buffer, 1000, fp)) != NULL)
{
count++;
if (count == line)
fputs(newline, fptmp);
else
fputs(buffer, fptmp);
}
fclose(fp);
fclose(fptmp);
//strcat(fullpath, filename);
//printf("%s", fullpath);
ret = remove(filename);
if(ret == 0) {
printf("File deleted successfully");
} else {
printf("Error: unable to delete the file");
}
rename("tmp/replace.txt", "tmp/a.txt");
getch();
}
The output is constantly:
Error: unable to delete the file
btw once I try this outside the "tmp/" folder it works just fine
The /tmp folder has the sticky bit (s) set, and that means, that anyone can read and create/modify files in it, but only its owner (root) can remove them.
So, if is what you want your program to do, you should do it in some directory other than /tmp
Also, as jarmod pointed out, you shouldn't have a hardcoded filename for your temporary filename. You should use tmpfile or tmpnam for this purpose:
Instead of:
fptmp = fopen("tmp/replace.txt", "w");
Write:
fptmp = tmpfile();
The file will be automatically deleted when the file stream is closed.
(You can read a more about the /tmp dir here)
Related
I am trying to create a c program that reads the extensions of the files in its current working directory.
The program then creates folders that correspond to the extensions of the files. It then copies each file
from its cwd into the corresponding folder.
e.g:
hello.txt into created .txt folder
The code successfully creates folders for all the file extensions in the current directory, but crashes when it begins to copy.
Here is the whole code.
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <dir.h>
#include <stdlib.h>
#include <errno.h>
int main(void) {
FILE *input, *output; // Two files, input and output
char ch; // ch is used to assign characters from input file which will then be copied into the output file
char *exe = ".exe";
struct dirent *de;
DIR *dr = opendir("."); // Open directory for reading
printf("%s", dr->dd_name);
// If directory doesn't exist, quit
if(dr == NULL) {
printf("Can't open current directory.");
return 0;
}
// Loop first to create a directory corresponding to all
// extensions present in the current directory
while((de = readdir(dr)) != NULL) {
char *filename = de->d_name; // Get the filename
char *ext = strrchr(filename, '.'); // Get the extension
if(!(!ext || ext == filename)){ // Compare extension
int check = mkdir(ext);
if(!check)//Check if the directory was created
printf("Directory created successfully.\n");
else {
printf("Unable to create directory.\n");
}
}
}
// Close the directory so as to reset the pointer ready for the next read.
closedir(dr);
dr = opendir(".");
// Loop reading each file and checking which
// directory it corresponds to.
while((de = readdir(dr)) != NULL) {
char *filename = de->d_name; // Get the filename
char *ext = strrchr(filename, '.'); // Get the extension
if(!(!ext || ext == filename)){ // Check for a valid extension
DIR *file_ext_dir = opendir(ext); // Open the dir that corresponds to the extension of the file.
char *dir_name = file_ext_dir->dd_name; //Get the dir name of the opened directory
if(file_ext_dir && (strcmp(dir_name, "..") != 0)&& (strcmp(ext, exe) !=0) ) { //ignore .exe and the cwd
printf("Successfully opened: %s dir\n", file_ext_dir->dd_name);
char *output_path = strcat(dir_name, filename);
printf("Ready to copy files from %s to: %s\n", filename, output_path);
output = fopen(output_path, "a+"); // Open output.txt for appending, if doesn't exist, create it.
input = fopen(filename, "r"); // Open the input file ()'filename') for reading
while(1) { // Loop through the input file
ch = fgetc(input); // Get the current character
if(ch == EOF) break; // Stop if EOF is found
putc(ch, output); // Put current character from the input file into output.txt
}
fclose(input); // Close input file
fclose(output); // Close output file
closedir(file_ext_dir);
} else if(ENOENT == errno){ //Check if there is no such directory and handle the error
printf("Dir does not exist.");
}else {
continue; //Skip that file if for some reason the directory cannot be opened.
}
}
}
closedir(dr); // Close directory
printf("Created directories and copied all files to that correspond to them.");
return 0;
}
I want to check if there are any duplicates in a .txt file. I've wrote a code but it's not running. I'm not sure about opening the norep.txt file in "a+" mode. The idea is to put the first word of my text in the norep.txt file, then compare every word in the text.txt with the words in norep.txt and copy only the words I need in the file.
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *fd;
FILE *ft;
char aux[30];
char aux1[30];
int len;
fd = fopen("c:\\text.txt", "r");
if (fd == NULL) {
puts("Error");
}
ft = fopen("c:\\norep.txt", "a+");
if (ft == NULL) {
puts("Error");
}
fscanf(fd, "%s", aux);
fprintf(ft, "%s", aux);
rewind(fd);
rewind(ft);
while (!feof(fd)) {
fscanf(fd, "%s", aux);
while (!feof(ft)) {
fscanf(ft, "%s", aux1);
len = strcmp(aux, aux1);
if (len != 0) {
fprintf(ft, "%s", aux);
}
}
rewind(ft);
}
return 0;
}
You should flush the output file before you rewind it.
fflush - flush a stream or fflush
Of course, this will not fix your problem because:
Note below that the manual says that reposition operations are ignored so that your attempt to read will always find the end of file.
append: Open file for output at the end of a file. Output operations
always write data at the end of the file, expanding it. Repositioning
operations (fseek, fsetpos, rewind) are ignored. The file is created
if it does not exist.
What you should probably do is create an internal memory table that keeps all the unique entries and write it out to a new file after all processing is done. As you read the fd file, check the list and add a new entry if it is not already in the list. Then after you have finished processing fd, then and only then write out your list. Of course, this may be too big depending on the size of your data file.
You could append each unique entry to the output file as you go. but you would need to have some method of checking the previous entries without trying to read the output file.
The usual way to go about this is to read the input file word for word, store the necessary information in some way and then, after you have read all information from the file, write the desired output to the output file.
A rough skeleton of that approach might look like this:
int main()
{
const char *infile = "text.txt";
const char *outfile = "norep.txt";
FILE *in;
FILE *out;
char word[30];
// (1) Read all words
in = fopen(infile, "r"); // .. and enforce success
while (fscanf(in, "%29s", word) == 1) {
// store word somewhere
}
fclose(in);
// (2) Determine unique words somehow
// (3) Write out unique words
out = fopen(outfile, "w"); // .. and enforce success
for (i = 0; i < nunique; i++) {
fprintf(out, "%s\n", unique[i]);
}
fclose(out);
return 0;
}
The actual algorithm to fin the unique words is missing from this incomplete skeleton code.
If you really want to test the words in a file for uniqueness without using additional memory beyond the current word, you can open the input file twice, with independent file pointers. Then you can write a loop like so:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
const char *infile = "text.txt";
const char *outfile = "norep.txt";
FILE *in1;
FILE *in2;
FILE *out;
char word1[30];
char word2[30];
in1 = fopen(infile, "r");
in2 = fopen(infile, "r");
out = fopen(outfile, "w");
if (in1 == NULL || in2 == NULL || out == NULL) {
fprintf(stderr, "Could not open all required files.\n");
exit(1);
}
while (fscanf(in1, "%29s", word1) == 1) {
int count = 0;
while (fscanf(in2, "%29s", word2) == 1) {
if (strcmp(word1, word2) == 0) count++;
if (count > 1) break;
}
if (count == 1) fprintf(out, "%s\n", word1);
rewind(in2);
}
fclose(in1);
fclose(in2);
fclose(out);
return 0;
}
This will, of course, re-read the file as often as there are words in the file. Not a good approach to find the unique words in Moby-Dick. I recommend that you look into the memory-based approach.
I am trying to open a file in a subdirectory called "Files". I know how to open a file in a subdirectory if I know the name:
fopen("./Files/file.txt", "r");
However, I am trying to create a file that will open any and all files in the subdirectory without having to know the file names ahead of time. I am using the reaaddir() function to be able to locate the file name, however, I am not sure how to plug it into fopen to open and read the file. The readdir() function automatically saves the file name in dp_>d_name. Then If I do this:
fopen("./Files/dp->d_name", "r");
the program is going to try to open the file named "dp->d_name" rather than the file name stored at that location.
IF there is not a way to do this, is there a way to change the current working directory from within the program? Every file I want to open is within the same subdirectory, so that would be an acceptable solution.
Here is my code, for reference:
#include <stdio.h>
#include <dirent.h>
#include <string.h>
void readFile(int)
{
DIR *dir;
struct dirent *dp;
char * file_name;
char buffer[100];
FILE *out;
FILE *in;
char outName[] = "filenames.txt";
if (( out = fopen(outName, "w+")) == NULL )
{
printf("Can't open %s for writing.\n", outName);
return 2;
}
dir = opendir("./Files/");
while ((dp=readdir(dir)) != NULL)
{
if ( !strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
{
//do nothing...
}
else
{
if (( in = fopen( dp->d_name, "r")) == NULL)
{
printf("Can't open %s for writing.\n", dp->d_name);
return 2;
}
fgets(buffer, 100, in);
printf("\"%s\"\n", buffer);
}
}
closedir(dir);
fclose(out);
return 0;
}
you can create the full file location in another variable by joining "./Files/" before dp->d_name. you can either use strcat() for it or use create char* with enough size to store the entire location and then fill it using a for loop, and then use this variable in fopen. eg.
if dp->d_name = "f1.txt" then create a variable,
newFileName = "./Files/f1.txt" and then fopen(newFileName, "r");
I want to read a text file line by line, perform some checks, and if the line is not required, delete it.
I have done the code for reading line, but I don't know how to delete that line if it is not required by me.
Please help me find the simplest method for deleting the line.
Here is my code snippet what I tried:
char ip[32];
int port;
DWORD dwWritten;
FILE *fpOriginal, *fpOutput;
HANDLE hFile,tempFile;
hFile=CreateFile("Hell.txt",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
tempFile=CreateFile("temp.txt",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
WriteFile(hFile,"10.0.1.25 524192\r\n\r\n10.0.1.25 524193\r\n\r\n",strlen("10.0.1.25 524192\r\n\r\n10.0.1.25 524193\r\n\r\n"),&dwWritten,0);
fpOriginal = fopen("Hell.txt", "r+");
fpOutput = fopen("temp.txt", "w+");
while (fscanf(fpOriginal, " %s %d", ip, &port) > 0)
{
printf("\nLine1:");
printf("ip: %s, port: %d", ip, port);
char portbuff[32], space[]=" ";
sprintf(portbuff, "%i",port);
strcat(ip," ");
strcat(ip,portbuff);
if(port == 524192)
printf("\n Delete this Line now");
else
WriteFile(tempFile,ip,strlen(ip),&dwWritten,0);
}
fclose(fpOriginal);
fclose(fpOutput);
CloseHandle(hFile);
CloseHandle(tempFile);
remove("Hell.txt");
if(!(rename("temp.txt","Bye.txt")))
{
printf("\ncould not rename\n");
}
else
printf("\nRename Done\n");
//remove ("Hell.txt");
here's an example:
char* inFileName = "test.txt";
char* outFileName = "tmp.txt";
FILE* inFile = fopen(inFileName, "r");
FILE* outFile = fopen(outFileName, "w+");
char line [1024]; // maybe you have to user better value here
int lineCount = 0;
if( inFile == NULL )
{
printf("Open Error");
}
while( fgets(line, sizeof(line), inFile) != NULL )
{
if( ( lineCount % 2 ) != 0 )
{
fprintf(outFile, "%s", line);
}
lineCount++;
}
fclose(inFile);
fclose(outFile);
// possible you have to remove old file here before
if( !rename(inFileName, outFileName) )
{
printf("Rename Error");
}
You can copy all line wich does not contain the number 2 into a new file and then use the new file instead the old file
fp = fopen("File.txt", "r");
fp2 = fopen("File_copy.txt", "w");
while (fscanf(fp, " %s %d", string, &number) > 0) {
if(number != 2)
{
fprintf(fp2, "%s %d\n", string, number);
}
}
close(fp);
close(fp2);
remove("File.txt");
rename( "File_copy.txt", "File.txt" );
Another solution could be to write back to the same file (write back what you read out except for the lines you don't want) and use the Windows API function SetEndOfFile to truncate it when finished. This will probably be a bit messier to code but you won't need to create a second copy of the file so it's more efficient from a disk usage standpoint.
There are many to solve this problem one of them is, you can open another file for writing when you reach at a point where you don't want to write omit that paint and continue writing until end of file. Latterly you can delete old file and rename new file with old one.
if(number == 2)
{
continue;
}
else
{
writetofilefunction()
}
Suppose I have a list of ip that i don't want to copy in a text file. Here's what i do..
For example i don't want to copy 192.168.5.20...
In my temp.txt file i have ip's:
192.168.5.20
192.168.5.10
192.168.5.30
192.168.5.50
192.168.5.12
-
char *data = "192.168.5.20";
char buff[100];
FILE *in, *out;
in = fopen("/tmp/temp.txt", "r");
while(fgets(buff,sizeof(buff),in) !=NULL){
if(!strstr(buff, data)){
printf("copying to ip.txt\n");
out = fopen("/tmp/ip.txt", "a");
fprintf(out,"%s",buff);
fclose(out);
}
}
if(feof(in)){
printf("Closing file descriptor and renaming ip.txt to temp.txt\n");
fclose(in);
rename("/tmp/ip.txt", "/tmp/temp.txt");
}
It work's leaving 192.168.5.20 ip.. but my problem is when temp.txt have only one ip..
e.g 192.168.5.20
Now i want to ignore it so when i open up my temp.txt file it should be blank. but still ip 192.168.5.20 is there when i open up my temp.txt file?.. Why is it doing that?.
Thanks..
The file /tmp/ip.txt is only created when there is at least one line in /tmp/temp.txt that doesn't contain the pattern to be ignored.
if(!strstr(buff, data)){
printf("copying to ip.txt\n");
out = fopen("/tmp/ip.txt", "a");
fprintf(out,"%s",buff);
fclose(out);
}
So if /tmp/temp.txt contains only one line, and that contains the pattern to be ignored, no /tmp/ip.txt is created, and rename fails, setting errno to ENOENT.
Check that with
#include <errno.h>
#include <string.h>
int fail = rename("/home/dafis/Doesntexist", "/home/dafis/doesexist");
if (fail) {
int en = errno;
if (en)
perror(strerror(en));
}
If there is only 192.168.5.20 in the file temp.txt, you are not even entering the while loop. That means you are not opening (creating if not existing) ip.txt. So rename fails and temp.txt remains the same.
You can try changing your code as following
if (feof(in))
{
if(0 == out)
out = fopen("ip.txt", "a");
printf("\nrename returned %d",rename("ip.txt", "temp.txt"));
printf("Closing file descriptor and renaming ip.txt to temp.txt\n");
fclose(in);
}
Do add some NULL checks in the code. Saves precious time.
char *unwanted = "192.168.5.20";
char buff[100];
FILE *in, *out;
unsigned cnt;
in = fopen("/tmp/temp.txt", "r");
out = fopen("/tmp/ip.txt", "w");
if (!in || !out) exit(EXIT_FAILURE);
for (cnt=0; fgets(buff,sizeof buff,in) ; ){
if(strstr(buff, unwanted)) continue;
fprintf(out,"%s",buff);
cnt++;
}
fclose(out);
fclose(in);
/* note: this will maintain the original file if it **only** consists
** of lines with the (unwanted) pattern in it.
** IMHO you'd better do the rename unconditionally; an empty file
** would be the correct result if all the lines match.
*/
if(cnt){
printf("Closing file descriptor and renaming ip.txt to temp.txt\n");
rename("/tmp/ip.txt", "/tmp/temp.txt");
}