This code does not open file properly, it returns no such file or directory, although the path and privilege are there and no other program is using the file. How can I fix the error? I tried swapping the path and moving the file, the error is there still.
char string[105];
FILE* file = fopen("C:\\Users\\Public\\Documents\\a.txt", "r");
while (fgets(string, 100, file)) {
printf("%s", string);
}
It can be surprisingly tricky to open a simple file! Lots of things can go wrong. I recommend writing slightly more verbose code, like this:
#include <string.h>
#include <errno.h>
char* filename = "C:\\Users\\Public\\Documents\\a.txt";
char string[105];
FILE* file = fopen(filename, "r");
if (file == NULL) {
fprintf(stderr, "can't open %s: %s\n", filename, strerror(errno));
exit(1);
}
while (fgets(string, 100, file)) {
printf("%s", string);
}
The point is that the error message prints out both the name of the file it tried but failed to open, and the actual reason it couldn't open it. (Also, by storing the filename in a variable, you make it absolutely certain that the filename it prints in the error message is the filename it tried but failed to open.) It sounds like you already know that the error was "no such file or directory", but I'm not sure how you know this.
Even though I've been programming in C for a long time, sometimes I still have this problem. One thing I'll sometimes do is use my mouse to copy the exact filename string printed in the error message, the file the program said it couldn't open, the file I'm sure is really there, and paste it into a terminal window (or CMD or Powershell if you're on Windows), along with a directory-listing command, to see if the operating system can actually see the file. That is, for your example, the command I'd run is
dir C:\Users\Public\Documents\a.txt
but the point is that I would not actually type the pathname "C:\Users\Public\Documents\a.txt", instead I would copy and paste it out of the error message that the program printed. Sometimes there are surprising little impossible-to-spot differences between the filename you thought it was trying to open, versus the filename it was actually trying to open, and this exercise is a good way to let the computer help you find those differences.
Remember, too, that you'll get the error "No such file or directory" if there's no file by that name in the directory, or if the directory isn't there at all. For example, if you're trying to open the path
C:\Users\Public\Documents\a.txt
and the file a.txt keeps not being there, and you keep checking your home directory
C:\Users\Donkey\Documents
and you keep seeing that the file is there, it can be surprisingly easy to overlook what the real problem is. :-)
Addendum: You might be having an issue with the different Unix/Linux versus Windows file path separators, that is, / versus \. Usually, on a Windows machine, it's safest to use \, as you've done. (One very frequent mistake is to forget to double the backslashes, but it looks like you got that right.) Depending on your programming environment, if there's some level of Unix emulation going on, you can sometimes use Unix-style /, and it will automatically translate to \ for you. I've never heard of a situation where using \ made it not work (which is a possibility being explored in the comments), but you might experiment with that, perhaps trying
char* filename = "/c/Users/Public/Documents/a.txt";
or (less likely)
char* filename = "C:/Users/Public/Documents/a.txt";
Related
I am developing a command line application in C (linux environment) to edit a particular file format. This file format is a plain XML file, which is compressed, then encrypted, then cryptographically signed.
I'd like to offer an option to the user to edit this kind of file in an easy way, without the hassle of manualy extracting the file, editing it, and then compressing, encrypting and signing it.
Ideally, when called, my application should do the following:
Open the encrypted/compressed file and extract it to a temporary location (like /tmp)
Call an external text editor like nano or sublime-text or gedit depending on which is installed and maybe the user preferences. Wait until the user have edited the file and closed the text editor.
Read the modified temporary file and encrypt/compress it, replacing the old encrypted/compressed file
How can I achieve point no. 2?
I thought about calling nano with system() and waiting for it to return, or placing an inotify() on the temp file to know when it is modified by the graphical text editor.
Which solution is better?
How can i call the default text editor of the user?
Anything that can be done in a better way?
First, consider not writing an actual application or wrapper yourself, which calls another editor, but rather writing some kind of plugin for some existing editor which is flexible enough to support additional formats and passing its input through decompression.
That's not the only solution, of course, but it might be easier for you.
With your particular approach, you could:
Use the EDITOR and/or VISUAL command-line variables (as also pointed out by #KamilCuk) to determine which editor to use.
Run the editor as a child process so that you know when it ends execution, rather than having to otherwise communicate with it. Being notified of changes to the file, or even to its opening or closing, is not good enough, since the editor may make changes multiple files, and some editors don't even keep the file open while you work on it in them.
Remember to handle the cases of the editor failing to come up; or hanging; or you getting some notification to stop waiting for the editor; etc.
Call an external text editor like nano or sublime-text or gedit depending on which is installed and maybe the user preferences. Wait until the user have edited the file and closed the text editor.
Interesting question. One way to open the xml file with the user's default editor is using the xdg-open, but it doesn't give the pid of the application, in which user will edit the file.
You can use xdg-mime query default application/xml to find out the .desktop file of the default editor, but then you have to parse this file to figure out the executable path of the program - this is exactly how xdg-open actually works, in the search_desktop_file() function the line starting with Exec= entry is simply extracted from the *.desktop to call the editor executable and pass the target file as argument... What I am trying to say, is, after you find the editor executable, you can start it, and wait until it's closed, and then check if the file content has been changed. Well, this looks like a lot of unnecessary work...
Instead, you can try a fixed well-known editor, such as gedit, to achieve the desired workflow. You can also provide user a way (i.e. a prompt or config file) to set a default xml editor, i.e. /usr/bin/sublime_text, which then can be used in your programm on next run.
However, the key is here to open an editor that blocks the calling process, until user closes the editor. After the editor is closed, you can simply check if the file has been changed and if so, perform further operations.
To find out, if the file contents have been modified, you can use the stat system call to get the inode change time of the file, before you open the file, and then compare the timestamp value with the current one once it is closed.
i.e.:
stat -c %Z filename
Output: 1558650334
Wrapping up:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void execute_command(char* cmd, char* result) {
FILE *fp;
fp = popen(cmd, "r");
fscanf (fp, "%s" , result);
}
int get_changetime(char* filename) {
char cmd[4096];
char output[10];
sprintf(cmd, "stat -c %%Z %s", filename);
execute_command(cmd, output);
return atoi(output);
}
int main() {
char cmd[4096];
char* filename = "path/to/xml-file.xml";
uint ctime = get_changetime(filename);
sprintf(cmd, "gedit %s", filename);
execute_command(cmd, NULL);
if (ctime != get_changetime(filename)) {
printf("file modified!");
// do your work here...
}
return 0;
}
I have a project where the user can open files by selecting them in a menu.
I have two near identical pieces of code, but one works, whereas the other doesn't:
the one that works is for opening text files through gedit ("chemin" contains the file path):
char buf[200];
snprintf(buf,sizeof(buf),"gedit %s",chemin);
system(buf);
And this one doesn't work when run in my code, but does work when run outside of it (opens .jpg files with eog - have also tried xdg with no improvement):
snprintf(buf,sizeof(buf),"eog %s",chemin);
system(buf);
Is there a surer way of opening .jpg files from the unix command line? Or did I forget something?
TIA
UPDATE
It seems the buffer only prints its first 7 characters to the command line, ie:
my file path: ./FICHIER_PROJET/basededonnee/basedeDonneefichier/IMG_RGB/21.jpg
what the command line prints: eog ./FI
This only happens with these .jpg files
The problem might come from the char '\0' that has the wrong place, try something like :
strncpy(buf, "eog ", 4);
strncat(buf, chemin, sizeof(chemin));
buf[4+sizeof(chemin)] = '\0';
if(system(buf) == -1){
perror("Error with the system call ");
exit(-1);
}
Solved it... I had been using one general buffer for all my system commands. I created a new buffer just for this one and it works.
I have to do a simple task. I have to open a file which is in a directory. I have the .c file in src, when I compile I move the programs (a.out) in the a bin directory. I want to read a file in the directory asset. All these folders are in a main folder.
If I do this
FILE* fp = fopen("../asset/team_list", "r");
it won't open the file. Why can't I open the file in that directory?
guess you forgot to put the extension of your file
FILE* fp = fopen("../asset/team_list.doc", "r");
Find what error you get using perror/explicit mention of error message and expect a possible reply from stackoverflow.
Make sure you are pointing out to the correct directory where the file is present from the PWD from where your program is being executed.
Relative paths are relative to the current working directory of the process, which might not be the same location as the binary file. So, if you are in /home/user/ and you run ./project/bins/my.exe then your current working directory is /home/user/, relative paths need to be relative to that location.
You can try a few things to help with this issue. First, after the failed open you could examine errno to see why the open failed, is it permissions, invalid path?
Alternatively you might have access to the strace program, this traces system calls, like open from your application, and will allow you to see the failed system call. Try strace ./project/bins/my.exe, you'll see a lot of output, dig through this looking for the failed open call, and try to figure out why this is failing, again the errno will be included in the trace to help understand the failure.
Lastly, you could just add a call to getcwd to your program and print the result (as a debugging aid), this places the current working directory into a buffer, something like this:
char buffer [PATH_MAX + 1];
getcwd (buffer, PATH_MAX + 1);
printf (buffer);
static char filename[128] = "trace.txt";
g_file = fopen(filename, "w");
if(NULL == g_file)
{
printf("Cannot open file %s.error %s\n",filename,strerror(errno));
exit(1);
}
I am trying to open a empty text file named trace.txt in write mode (in my working directory.)
The program is creating an empty file trace.txt in my directory.but the check (NULL == g_file)
is returning true and it is returning error code 24 (Too many open files.).Any idea why this is.This is the first file I am opening in my program.
Surprisingly the code is creating an empty file in my working directory by the name specified.However the check for null file pointer is succeeding for some reason.? :(
You probably have a file descriptor leak.
If your code keeps opening files, never closing them, you will reach the limit sooner or later, and then fopen will fail.
You can check this by printing the file descriptor numbers you get whenever opening a file. If they keep growing, you have a leak.
It is most likely due to your system reaching its maximum allowed open file handles.
You can easily test this by running the following:
$ dd if=/dev/urandom of=test.dat bs=16 count=1
If you are out of file handles, this should provide the same or similar error.
You can trouble shoot this using some of the following commands:
To see the maximum allowed open files:
$ cat /proc/sys/fs/file-max
To see the which files are currently open (remember this includes device files, sockets, etc):
$ lsof
You can also use lsof to get a count of open files:
$ lsof | wc -l
This looks like a similar issue to what you're having, but I'm not entirely sure if it will help you solve the problem. Might be worth a look:
Problem with writing to file in C
Correct, I faced same error message and found that I was trying to close the file in a function but not where it was opened. So I then closed in the function where it was opened, later everything went fine.
I have some code which iteratively appends data to a file and looks similar to:
for(int i=0; i<number; i++){
FILE *log_file;
char name[50];
sprintf(name,"something_%d.log",i);
log_file=fopen(name,"a");
if(log_file == NULL){
printf("ERROR cannot open file %s",name);
abort();
}
/* Write stuff to file */
fclose(log_file);
}
Seems simple enough right? If the file exists and I have permission to write to it, it proceeds as normal; if the file does not exist and I have permission to write files in the directory, it creates the file as normal. WRONG! Somehow, when I come across a particular file name (MINI_3f_1_0.log) the program cannot create/open the file and yields log_file = NULL. Obviously this is not my entire code, and the worst thing is that I cannot reproduce this problem with a simple program as shown.
I have already spent a few hours trying to track down what is going on, and so far I am 100% sure of the following:
The file is declared, opened, and closed within the same scope
A file of the same name is not open in any other function/the entire program
I have permission to read/write in the directory
Trying to open the file out of the iterative order produces the same error when it is done in the same routine
Any guidance you guys/gals can give me would be greatly appreciated. If you have come across anything like this in your experience, how did you fix it?
As suggested by Mat in the comments,running the code in a different directory did not produce the error. There is something likely wrong with the file system and needs to be looked into by the sys-admin.