Reputation: 35
I am making a program that takes a file and creates a new file which has the contents of the original file in reverse order.
I am able to do it but every time I write into the file all the content is correct, but there are random symbols that keep changing in the beginning of the output file
I was trying to reverse the text from this source https://norvig.com/big.txt
Expected output
iP ot denrut niaga eh dnA
.stnerap rehto gnitatimi yb deriuqca ylno dah ilisaV ecnirP
hcihw tub ,doohybab morf nerdlihc rieht dettep evah ohw stnerap ot
larutan ssenrednet lautibah fo enot sselerac eht htiw reh gnisserdda
dna rethguad sih ot yltnatsni gninrut ,deksa eh "?ayleL ,lleW"
although I do get this output sometimes, most of the time I am getting an output like this
����iP ot denrut niaga eh dnA
.stnerap rehto gnitatimi yb deriuqca ylno dah ilisaV ecnirP
hcihw tub ,doohybab morf nerdlihc rieht dettep evah ohw stnerap ot
larutan ssenrednet lautibah fo enot sselerac eht htiw reh gnisserdda
dna rethguad sih ot yltnatsni gninrut ,deksa eh "?ayleL ,lleW"
I don't know why I am getting these special characters, they are not the same all the time, they keep changing and sometimes they are not there at all and give the correct output.
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
size_t getFilesize(const char* filename) {
struct stat st;
if(stat(filename, &st) != 0) {
return 0;
}
return st.st_size;
}
void reverse(char s[])
{
int i, j;
char c;
for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
void itoa(int n, char s[])
{
int i, sign;
if ((sign = n) < 0) /* record sign */
n = -n; /* make n positive */
i = 0;
do { /* generate digits in reverse order */
s[i++] = n % 10 + '0'; /* get next digit */
} while ((n /= 10) > 0); /* delete it */
if (sign < 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);
}
int main( int argc , char *argv[] ){
int sz,fd,fd2;
int seekStatus;
int writeStatus;
int fileSize;
char c[100000];
fd = open(argv[1],O_RDONLY);
if (fd < 0) {
perror("input file missing");
exit(1);
}
mkdir("Output", 0700);
fd2 = open("Output/A.txt", O_WRONLY | O_CREAT | O_TRUNC, 0700);
fileSize= getFilesize(argv[1]);
int progress = 0;
char strprogress[100];
int chunk;
chunk = 100000;
int i = -1;
if (fileSize<chunk ){
seekStatus=lseek(fd, -1, SEEK_END);
while (seekStatus >= 0 ){
sz=read(fd,c,1);
writeStatus=write(fd2, c , 1);
progress= ((-1.0 * i / fileSize)) * 100 ;
itoa(progress,strprogress);
write(1,"\r",1);
write(1,strprogress, strlen(strprogress));
i=i-1;
seekStatus=lseek(fd, i, SEEK_END);
}
}
else{
int k = 1; // iterator
seekStatus=lseek(fd, -1*k*chunk, SEEK_END);
while (seekStatus >=0){
sz = read(fd , c ,chunk);
reverse(c);
writeStatus=write(fd2, c , chunk);
progress= ((-1.0 * chunk * k / fileSize)) * 100 ;
write(1,"\r",1);
write(1,strprogress, strlen(strprogress));
k=k+1;
seekStatus=lseek(fd, -1*k*chunk, SEEK_END);
}
int remaining;
remaining = fileSize - (k*chunk);
if ( remaining != 0 ){
seekStatus=lseek(fd, fileSize-remaining, SEEK_END);
sz = read(fd , c ,remaining);
write(fd2, c , remaining);
write(1,"\r",1);
write(1,"100",strlen("100"));
}
}
}
Basically, what I am trying to do in my program is that I am reading the file 1000 bytes at a time reversing and then writing it into the file when the number of bytes left is less than thousand, I am just writing one byte at a time. I also have a progress status that gets written to the screen.
Upvotes: 1
Views: 480
Reputation: 43280
First of all, this code is very wrong.
sz = read(fd , c ,chunk);
reverse(c);
writeStatus=write(fd2, c , chunk);
read
reads bytes in arbitrary amounts. I can't imagine wanting to reverse arbitrary amounts, so this is probably not what you want. For this use case, we appear to want readblock
and writeblock
. You don't have them in your library.
ssize_t readblock(int fd, void *outptr, size_t len)
{
void *ptr = outptr;
int delta;
while (len) {
delta = read(fd, ptr, len);
if (delta < 0) return -1;
if (delta == 0) { return ptr - outptr; }
ptr += delta;
len -= delta;
}
return ptr - outptr;
}
ssize_t writeblock(int fd, const void *inptr, size_t len)
{
const void *ptr = inptr;
int delta;
while (len) {
delta = write(fd, ptr, len);
if (delta < 0) return -1;
if (delta == 0) { errno = ENOSPC; return -1; }
ptr += delta;
len -= delta;
}
return ptr - inptr;
}
If you're not using gcc
, this won't compile. This kind of code is what this gcc
extension is for. Change ptr
's type to char *
.
But your code still doesn't work. There's one more thing we need to address. The final chunk doesn't happen. We need to pass size in.
int oldseekstatus = 0;
//...
seekstatus = lseek(fd, 0, SEEK_END);
oldseekstatus = seekstatus;
seekStatus=lseek(fd, -1*k*chunk, SEEK_END);
while (seekStatus >=0) {
sz = read(fd , c ,chunk);
reverse(c, sz);
writeStatus=write(fd2, c , chunk);
//...
k=k+1;
oldseekstatus = seekstatus;
seekStatus=lseek(fd, -1*k*chunk, SEEK_END);
}
if (oldseekstatus > 0 {
lseek(fd, 0, SEEK_END);
sz = read(fd , c ,chunk);
reverse(c, sz);
writeStatus=write(fd2, c , chunk);
}
And let's deal with reverse
void reverse(char s[], size_t sz)
//...
for (i = 0, j = sz-1; i<j; i++, j--) {
//...
Upvotes: 1