How do I modify the stream from one file to another - c

I need to make a program that takes string data from one file and copy every third char from it to another file.
I am not sure if I am doing it right. The idea I got is to first create one array where I will store original data from file1 and then using 'for' loop I will modify the data and store in in the second array:
(eg for(i=0; i < arraysize; i+=3);
The thing is I dont have an idea how to transfer input to my array and how to do it backwards to have my modified data go to file2.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define BUFFER_SIZE 50
int main(int argc, char *argv[]) {
char buffer[BUFFER_SIZE];
char modified[BUFFER_SIZE];
int input_fd, output_fd;
ssize_t ret_in, ret_out;
if(argc !=3 || strcmp(argv[1], "--help") == 0)
{
printf("Usage: %s file_origin file_destination\n", argv[0]);
return 2;
}
input_fd = open(argv[1], O_RDONLY);
if(input_fd == -1)
{
perror("There is no such file");
return 2;
}
out_fd = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0644);
if(output_fd == -1)
{
perror("create");
return 3;
}
Could someone please tell me how to use function read/write correctly to stream my data to array and how to do it the other way.

Welcome to Stackoverflow!
Given the exact description of your assignment, I would not use a buffer; you could simply read from the input file one byte at a time, and write every third byte to the output file. This avoids any buffer-management overhead.
But, if you do read from the input file into a buffer, you do not need to modify that buffer in any way, nor do you need a second buffer. After reading all the data, simply iterate through the input buffer, outputting every third byte to the output file.
But, if you want/need to reuse the output in some way, you can simply populate a second buffer from the input buffer in the same manner (loop over the input buffer, skipping two bytes each iteration), and then write that second buffer to the output file. (This way, you still have the same output in that second buffer, and you can reuse it in some manner.)
The approach you take will dictate the best functions to use. I see you already know about open(). Read up on read(), write() and close(), but also read up on fopen(), fgetc(), fgets(), fread(), fwrite() and fclose(). There is a lot for you to learn from reading about these various functions, how they are similar to each other, how they differ from each other, and the pros and cons of each. Reading about them will lead you to learn about other related file operations (like seeking, rewinding, etc.), which will serve you well as you learn more about C and programming in general.
Please note that for the approaches using buffers, you need to be very careful about the size of your buffers vs. the size of the input file. There are many pitfalls here. If this is an assignment for a class of some sort, then those considerations might show up in later lessons / assignments, and maybe it's too much to take on just now. But it's never too early to start thinking about what you do and don't know about the input your program will need to handle.

If you do not need cin or cout, I would suggest the following (I assumed strings are ended with newline and those should be preserved in the output and that counting the 3rd character starts anew in every line read):
FILE *f1=fopen("_infile.txt","rt");
FILE *f2=fopen("_outfuile.txt","wt");
char buffer[MAXBUFLEN];
while (!feof(f1)) {
if (fgets(buffer,MAXBUFLEN,f1)>0) {
for(int i=2;i<strlen(buffer);i+=3) {
fprintf(f2,"%c",buffer[i]);
}
fprintf(f2,"\n");
} else break;
}
fclose(f1);
fclose(f2);

This will read input file and reprint every third character to output. You can adapt it to you situation.
#include <stdio.h>
#include <stdlib.h>
int main()
{
size_t i; // index
int c; // char read
FILE *FIN, *FOUT; // file streams
if ((FIN = fopen("in.txt", "rb")) == NULL) {
printf("Error opening input file.\n Exiting.\n");
exit(1);
}
if ((FOUT = fopen("out.txt", "wb")) == NULL) {
printf("Error opening output file.\n Exiting.\n");
exit(1);
}
// read input and reprint every third character
for(i=0;;i++)
{
c = fgetc(FIN); // read byte
if(c == EOF)
{
break; // reached end of file (input), leave loop
}
if((i%3)==2) // get every third character by modulo(i)
{
fputc(c, FOUT); // write output
}
}
fclose(FIN);
fclose(FOUT);
return 0;
}

Related

Sort a binary file with qsort

EDIT 3
THE FILE CONTAINS BYTES - I guess I have to sort the bytes, the task doesn't say more - it says that I pass an argument - the name of a binary file that contains bytes - that's it. And I am trying to work with low-level funcs.
I am trying to sort a binary file using qsort but I got stuck - I dont know how to write the content of a file to a buffer so I could pass it to qsort
What I have done:
int main(int argc, char*argv[]){
int fd1;
if((fd1=open(argv[1], O_RDONLY))==-1){
printf("Error occurred while opening the file");
exit(-1);
}
int size;
char c;
while(read(fd1, &c, 1)){
size=size+1;
}
size=size+1;
close(fd1);
fd1=open(argv[1], O_RDONLY);
if(fd1==-1){
printf("Error occured while opening the file");
}
char*buffer;
buffer=malloc(size);
setbuf(fd1, buffer);
//EDIT I TRIED THIS AND IT STILL DOES NOT WORK
int i=0;
while(read(fd1, &c, 1)){
buffer[i]=c;
i++;
}
for(int i=0; i<size;i++){
printf("lele %s", buffer[i]);
}
//EDIT 2: after making buffer[i]=c I get this error Segmentation fault
}
SetBuf does not work this way.. How to make it work? Also, I am trying to use func like open, close, read, write, etc.
Your algorithm for reading a file into a buffer is good:
Open the file
Count bytes in file
Close the file
Allocate the buffer
Open the file
Read the file
Close the file
A bit inefficient, because you read the file twice, but that's fine. You just have to implement it properly; any small mistake will make it look like it doesn't work. Use a debugger to check each step.
Here is my try. I didn't debug, to not deny you the "fun" of debugging. I put comments instead.
int main(int argc, char*argv[])
{
// 1. Open the file
int fd1;
if((fd1=open(argv[1], O_RDONLY))==-1){
printf("Error occurred while opening the file");
exit(-1);
}
// 2. Count bytes in file
int size = 0;
char c;
while(read(fd1, &c, 1))
size=size+1;
// To check that this part is good, print the size here!
// 3. Close the file
close(fd1);
// Allocate the buffer
char *buffer;
buffer = malloc(size);
// Might want to print the buffer here, to make sure it's not NULL
// 5. Open the file
fd1=open(argv[1], O_RDONLY);
if(fd1==-1){
printf("Error occurred while opening the file");
}
// 6. Read the file
for (int index = 0; index < size; ++index)
read(fd1, &buffer[index], 1);
// Might want to print what "read" returns in each iteration, to make sure it's successful
// 7. Close the file
close(fd1);
}
As noted by Eric Postpischil, the algorithm is actually not good.
The size of the file at one time does not guarantee the size at another time.
If you want to do that correctly, you must read the file only once. This will make the allocation harder: you cannot calculate the required buffer size, so you have to "guess" an initial size and use realloc.
However, in this small example, this is clearly not the requirement - you can probably ignore the possibility of the file changing asynchronously.
There is another possible problem - I/O error on the file when you read it the second time. This is easy to check, so maybe you should add it.

Check multiple files with "strstr" and "fopen" in C

Today I decided to learn to code for the first time in my life. I decided to learn C. I have created a small program that checks a txt file for a specific value. If it finds that value then it will tell you that that specific value has been found.
What I would like to do is that I can put multiple files go through this program. I want this program to be able to scan all files in a folder for a specific string and display what files contain that string (basically a file index)
I just started today and I'm 15 years old so I don't know if my assumptions are correct on how this can be done and I'm sorry if it may sound stupid but I have been thinking of maybe creating a thread for every directory I put into this program and each thread individually runs that code on the single file and then it displays all the directories in which the string can be found.
I have been looking into threading but I don't quite understand it. Here's the working code for one file at a time. Does anyone know how to make this work as I want it?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
//searches for this string in a txt file
char searchforthis[200];
//file name to display at output
char ch, file_name[200];
FILE *fp;
//Asks for full directory of txt file (example: C:\users\...) and reads that file.
//fp is content of file
printf("Enter name of a file you wish to check:\n");
gets(file_name);
fp = fopen(file_name, "r"); // read mode
//If there's no data inside the file it displays following error message
if (fp == NULL)
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
//asks for string (what has to be searched)
printf("Enter what you want to search: \n");
scanf("%s", searchforthis);
char* p;
// Find first occurrence of searchforthis in fp
p = strstr(searchforthis, fp);
// Prints the result
if (p) {
printf("This Value was found in following file:\n%s", file_name);
} else
printf("This Value has not been found.\n");
fclose(fp);
return 0;
}
This line,
p = strstr(searchforthis, fp);
is wrong. strstr() is defined as, char *strstr(const char *haystack, const char *needle), no file pointers in it.
Forget about gets(), its prone to overflow, reference, Why is the gets function so dangerous that it should not be used?.
Your scanf("%s",...) is equally dangerous to using gets() as you don't limit the character to be read. Instead, you could re-format it as,
scanf("%199s", searchforthis); /* 199 characters + \0 to mark the end of the string */
Also check the return value of scanf() , in case an input error occurs, final code should look like this,
if (scanf("%199s", searchforthis) != 1)
{
exit(EXIT_FAILURE);
}
It is even better, if you use fgets() for this, though keep in mind that fgets() will also save the newline character in the buffer, you are going to have to strip it manually.
To actually perform checks on the file, you have to read the file line by line, by using a function like, fgets() or fscanf(), or POSIX getline() and then use strstr() on each line to determine if you have a match or not, something like this should work,
char *p;
char buff[500];
int flag = 0, lines = 1;
while (fgets(buff, sizeof(buff), fp) != NULL)
{
size_t len = strlen(buff); /* get the length of the string */
if (len > 0 && buff[len - 1] == '\n') /* check if the last character is the newline character */
{
buff[len - 1] = '\0'; /* place \0 in the place of \n */
}
p = strstr(buff, searchforthis);
if (p != NULL)
{
/* match - set flag to 1 */
flag = 1;
break;
}
}
if (flag == 0)
{
printf("This Value has not been found.\n");
}
else
{
printf("This Value was found in following file:\n%s", file_name);
}
flag is used to determine whether or not searchforthis exists in the file.
Side note, if the line contains more than 499 characters, you will need a larger buffer, or a different function, consider getline() for that case, or even a custom one reading character by character.
If you want to do this for multiple files, you have to place the whole process in a loop. For example,
for (int i = 0; i < 5; i++) /* this will execute 5 times */
{
printf("Enter name of a file you wish to check:\n");
...
}

How to read an integer and a char with read() function in C?

I'm working on linux, I have a file that contains a line like this:
328abc
I would like, in C, to read the integer part (328) and the characters 'a','b','c', using only the function:
ssize_t read (int filedes, void *buffer, size_t size))
This is the only thing the file contains.
I know there are better ways to do that with other functions, but I haven't coded in C for a long time, and trying to help a friend, only this function is alowed.
How do I play with the buffer to do that?
Thanks
edit:
I understand that I need to parse the buffer manually. and my question is how?
If that's the only thing in the file. This will do:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main() {
char buffer[6];
char intBuffer[4];
ssize_t bytesRead;
int number;
int fd;
if ((fd = open("file.txt", O_RDONLY)) == -1) {
perror("Error opening file");
exit(EXIT_FAILURE);
}
if ((bytesRead = read(fd, buffer, 6)) == -1) {
perror("Error reading file");
exit(EXIT_FAILURE);
}
memcpy(intBuffer, buffer, 3);
intBuffer[3] = '\0';
number = atoi(intBuffer);
printf("The number is %d\n", number);
exit(EXIT_SUCCESS);
}
The following code will print "The number is 328".
Is this some kind of homework?
I am asking because there are better ways to do that than using the read function.
Anyway to answer your question, read reads size bytes from the file whose file descriptor is filedes and places them to the buffer.
It does not know anything about line breaks etc. So you need to manually find where a line ends, etc. If you want to only use read, then you need to manually parse the buffer after each call to read (supposing your files contains many lines, that you want to parse).
Beware that a line may be split between two read calls, so you need to handle that case with caution.

How do i read a file backwards using read() in c? [duplicate]

This question already has answers here:
Reading a text file backwards in C
(5 answers)
Closed 9 years ago.
I am supposed to create a program that takes a given file and creates a file with reversed txt. I wanted to know is there a way i can start the read() from the end of the file and copy it to the first byte in the created file if I dont know the exact size of the file?
Also i have googled this and came across many examples with fread, fopen, etc. However i cant use those for this project i can only use read, open, lseek, write, and close.
here is my code so far its not much but just for reference:
#include<stdio.h>
#include<unistd.h>
int main (int argc, char *argv[])
{
if(argc != 2)/*argc should be 2 for correct execution*/
{
printf("usage: %s filename",argv[0[]);}
}
else
{
int file1 = open(argv[1], O_RDWR);
if(file1 == -1){
printf("\nfailed to open file.");
return 1;
}
int reversefile = open(argv[2], O_RDWR | O_CREAT);
int size = lseek(argv[1], 0, SEEK_END);
char *file2[size+1];
int count=size;
int i = 0
while(read(file1, file2[count], 0) != 0)
{
file2[i]=*read(file1, file2[count], 0);
write(reversefile, file2[i], size+1);
count--;
i++;
lseek(argv[2], i, SEEK_SET);
}
I doubt that most filesystems are designed to support this operation effectively. Chances are, you'd have to read the whole file to get to the end. For the same reasons, most languages probably don't include any special feature for reading a file backwards.
Just come up with something. Try to read the whole file in memory. If it is too big, dump the beginning, reversed, into a temporary file and keep reading... In the end combine all temporary files into one. Also, you could probably do something smart with manual low-level manipulation of disk sectors, or at least with low-level programming directly against the file system. Looks like this is not what you are after, though.
Why don't you try fseek to navigate inside the file? This function is contained in stdio.h, just like fopen and fclose.
Another idea would be to implement a simple stack...
This has no error checking == really bad
get file size using stat
create a buffer with malloc
fread the file into the buffer
set a pointer to the end of the file
print each character going backwards thru the buffer.
If you get creative with google you can get several examples just like this.
IMO the assistance you are getting so far is not really even good hints.
This appears to be schoolwork, so beware of copying. Do some reading about the calls used here. stat (fstat) fread (read)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
int main(int argc, char **argv)
{
struct stat st;
char *buf;
char *p;
FILE *in=fopen(argv[1],"r");
fstat(fileno(in), &st); // get file size in bytes
buf=malloc(st.st_size +2); // buffer for file
memset(buf, 0x0, st.st_size +2 );
fread(buf, st.st_size, 1, in); // fill the buffer
p=buf;
for(p+=st.st_size;p>=buf; p--) // print traversing backwards
printf("%c", *p);
fclose(in);
return 0;
}

I/O issues writing on file

I'm having a hard time trying to figure out why this piece of code doesn't work as it should. I am learning the basics of I/O operations and I have to come up with a C program that writes on a 'log.txt' file what is given from standard input and as the 'stop' word is entered, the program must halt.
So my code is:
#include "main.h"
#define SIZE 1024
int main(int argc, char *argv[])
{
int fd;
int readBytes;
int writBytes;
char *buffer;
if ((fd = open("log.txt", O_WRONLY|O_APPEND)) < 0)
{
perror("open");
}
buffer = (char *) calloc (SIZE, sizeof(char));
while ((readBytes = read(0, buffer, SIZE) < SIZE)&&(strncmp(buffer, "stop", 4) != 0));
if ((writBytes = write(fd, buffer, SIZE)) < 0)
{
perror("write");
}
if ((close(fd)) < 0)
{
perror("close");
}
}
If I enter:
this is just a text
stop
The output is
stop
is just a text
If I enter more than a sentence:
this is just a text
this is more text
and text again
stop
This is what is logged:
stop
ext again
xt
t
And on top of that if I try to edit the log.txt file from vim or just a text editor I can see '\00's. I guess \00 stands for all the bytes left empty from the 1024 available, right? How can I prevent that from happening?
It looks like you're expecting
readBytes = read(0, buffer, SIZE) < SIZE)
to somehow accumulate things in buffer. It doesn't. Every subsequent read will put whatever it read at the start of the buffer, overwriting what the previous read has read.
You need to put your write in the while block - one write for every read, and only write as much as you read, otherwise you'll write garbage (zeros from the calloc and/or leftovers from the previous read) in your log file.
Also note that while your technique will probably work most of the time for a line-buffered input stream, it will not do what you expect if you redirect from a file or a pipe. You should be using formatted input functions (like getline if you your implementation has that, scanf, or fgets).

Resources