System copy file with space - c++

By using system command prompt copy in C++, I could not perform the command as my directory has space in between two character, the 'log' and 'file'. Maybe regular expression may help me solve this problem. But I had no ideas how to do this.
system("copy C:\users\person\log file C:\users\person\desktop")

system("copy \"C:\\users\\person\\log file\" C:\\users\\person\\desktop")
I haven't tested that, but it should work.

I believe #tabstop was referring to "std::rename", which is one solution. The way that you are copying the file will only work if there is a command called "copy" on the operating system. If you were to run this program on, say, iOS, it would not work.
Here is a better way of doing this in a C++ way (solution grafted from here: Copy a file in a sane, safe and efficient way)....
#include <fstream>
int main(char** argv, int argc)
{
std::ifstream src("C:\\users\\person\\log file", std::ios::binary);
std::ofstream dst("C:\\users\\person\\desktop", std::ios::binary);
dst << src.rdbuf();
}
Don't forget the extra backslashes. You need them because the backslash is an escape character that will turn on or off functionality (like \n for the newline).

Related

Disabling Ctrl-Z behaviour in `ifstream::getline`

I want to use ifstream::getline to read lines from a file, but the file contains the byte Ctrl-Z (0x1A), which makes getline think that it's reached the end of file (this is in Windows -- in *nix it would be Ctrl-D, if I'm not wrong). Can I disable this behaviour somehow, and tell getline to ignore Ctrl-Z?
Just for info: the file is comments.wast in the WebAssembly testsuite, which tests the ability of a WebAssembly parser to accept any and all characters inside a block comment.
This shouldn't happen when your ifstream object is using binary mode.
Just create it like this:
std::ifstream fin(<path>, std::ios::binary)
This of course prevents you from using other features of the stream, but if your main goal is to be able to read all sort of values while ignoring special characters, this is probably the way to go.

C++: Getting size of all files inside current directory

I'm new to C++ programming, and I'm trying to practice file reading and writing. I'm trying to get the sizes of all the files of the current directory. Thing is, after getting the names of the files in the current directory, I place them inside of a text file. So now I'm stuck, and don't know where to go from here.
#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std;
// FILE FUNCTION
void fileStuff(){
}
// MAIN FUNCTION
int main(int argc, char const *argv[])
{
// ERROR CHECKING
if(argc != 3){ // IF USER DOESN'T TYPE ./nameOfFile, AND THE OTHER REQUIRED ARGUMENTS.
cout << "Incorrect. Try Again" << endl;
exit(-1);
}
ifstream file;
string fileContents;
system("find . -type f > temp.txt");
file.open("temp.txt");
if (!file){
cout << "Unable to open file: temp.txt" << endl;
exit(-1);
}
while(file){
getline(file, fileContents);
cout << fileContents << endl;
}
file.close();
return 0;
}
C++14 (and earlier versions, notably C++11) does not know about file systems and directories (yet). For C++17, see its file system library. Otherwise, your code is operating system specific, but Boost library has some file system support.
I am assuming you are running on Linux or some POSIX system.
Your program just uses an external command (find(1)); if you want to read from such a command, you might use popen(3) with pclose, then you won't need a temporary file. BTW, you could use find . -type f -ls.
However, you don't need to use an external command, and it is safer (and faster) to avoid that.
Pedantically, a file name could contain a newline character, and with your approach you'll need to special case that. A file name could also contain a tab character (or other control characters) and in that case find . -type f behave specifically, and you would also need to special case. In practice, it is extremely poor taste and very unlikely to have a newline or tab character in a file name and you might forget these weird cases.
You could use nftw(3). You could recursively use opendir(3) & loop on readdir(3) (and later closedir).
Once you have a file path, you would use stat(2) to get that file's metadata, including its size (field st_size). BTW the /bin/ls and /usr/bin/find programs use that.
The readdir(3) function returns a struct dirent pointer ending with d_name; you probably want to skip the two entries for . and .. (so use strcmp(3) to compare with "." and "..", or do the compare the hard way). Then you'll build a complete file path using string catenation. You might use (in genuine C++) std::string or you could use snprintf(3) or asprintf(3) for that. If you readdir the current directory . you could call stat(2) directly on d_name field.
BTW exit(-1) is incorrect (and certainly poor taste). See exit(3). A much more readable alternative is exit(EXIT_FAILURE)

C++ delete everything in text file that is located before/after a specific word

So lets say text file has the following contents:
kasjdfhjkasdhfjkasdhfjasfjs
asdjkfhasj
start
sdfjkhasdkjfhasjkdfhajksdfhjkasdfh
asdjfhajs
end
sdjfhsjkdf
How to delete everything before the word "start" and everything after "end"?
Filesystems in general do support "truncate" meaning to chop off the end, but they do not support removing the front of a file. So you're left with only one option: you need to move the contents between "start" and "end" to the beginning of the file, then "truncate" the rest. This isn't very efficient if the part you're moving is very large, but there's no way around it on typical filesystems.
Barring very specific cases, it is not a good idea to edit files in place. If your computer crashes at the wrong point in time, for instance, you'd end up with a corrupted file and without the ability to restore its state before the attempted transformation.
So, better to read from one file and write to another, which is very simple:
std::ifstream in ("input.txt");
std::ofstream out("output.txt");
std::string line;
// read and discard lines before "start"
while(std::getline(in, line) && line != "start");
// read and echo lines until "end"
while(std::getline(in, line) && line != "end") {
out << line << '\n';
}
and then move it to where the original file is, overwriting it. On Windows:
MoveFileExA("output.txt", "input.txt", MOVEFILE_REPLACE_EXISTING);
On POSIX-conforming systems (such as Linux, BSD, MacOS X):
rename("output.txt", "input.txt");
...or take a look at Boost.Filesystem for a portable solution.
Renaming will typically be an atomic operation for the file system, so you'll have the state before or after the transformation at all times, and if fecal matter hits the fan, you'll be able to repair it without too much trouble.

Stuck with removing "\r" from text files! C++

OK so I've almost completed a program. However whilst it works on Windows I would prefer to run it on my Mac to test differences in performance (my Mac has much faster hardware).
I have an unordered map that is storing in values from a text file and I am also copying this map to reverse the key/value pairs.
The text files keep adding a new line, and from research I've found it to be because Windows adds it's own carriage return (why?!) and it's at the end of every second element in my map.
The file is "stringx,stringy" and so am using stringstream to split the string x and y into the key/value pair.
EDIT: thanks for the answers guys, worked a treat!
That isn't how std::string::replace works, you should read up on how it works here.
In order to do a basic replace, you could write your own function to do it, however in your case it seems to be a trimming issue since the carriage return is usually on the right side of the string.
You can remove the carriage return and new line by doing something like this:
std::string& rtrim(std::string& str) {
size_t endpos = str.find_last_not_of("\r\n");
if(endpos != std::string::npos) {
str.substr(0,endpos+1).swap(str);
}
return str;
}
On some implementations, like Windows, using a read mode of "r" or a write mode of "w" will cause "\r\n" to be read/written when you meant to pass "\n" through. Use "wb" or "rb". For iostream functions, I believe you need to pass in the ios::binary flag.
Windows uses "\r\n" to end lines. Usually programs that are supposed to run on various platforms use some #ifdef to handle similar differences.
I think I understand what the question is now. It's not about dealing with the differences in code - you are actually trying to use a "DOS/Windows" file on a non-Dos/Windows machine - you need to use dos2unix to fix up the end of lines on your file!

Read and write image data C++

I've just started learning C++, and I'm working on a program that is supposed to grab an image from the hard disk and then save it as another name. The original image should still remain. I've got it work with text files, because with those I can just do like this:
ifstream fin("C:\\test.txt");
ofstream fout("C:\\new.txt");
char ch;
while(!fin.eof())
{
fin.get(ch);
fout.put(ch);
}
fin.close();
fout.close();
}
But I suppose that it's not like this with images. Do I have to install a lib or something like that to get it work? Or can I "just" use the included libraries? I know I'm not really an expert of C++ so please tell me if I'm totally wrong.
I hope someone can and want to help me! Thanks in advance!
Btw, the image is a .png format.
You can use the std streams but use the ios::binary argument when you open the stream. It's well documented and there is several examples around the internet
You are apparently using MS Windows: Windows distinguishes between "text" and "binary" files by different handling of line separators. For a binary file, you do not want it to translate \n\r to \n on reading. To prevent it, using the ios::binary mode when opening the file, as #Emil tells you.
BTW, you do not have to use \\ in paths under windows. Just use forward slashes:
ifstream fin("C:/test.txt");
This worked even back in WWII using MS-DOS.
If the goal is just to copy a file then CopyFile is probably better choice than doing it manually.
#include <Windows.h>
// ...
BOOL const copySuccess = CopyFile("source.png", "dest.png", failIfExists);
// TODO: handle errors.
If using Windows API is not an option, then copying a file one char at a time like you have done is very inefficient way of doing this. As others have noted, you need to open files as binary to avoid I/O messing with line endings. A simpler and more efficient way than one char at a time is this:
#include <fstream>
// ...
std::ifstream fin("source.png", std::ios::binary);
std::ofstream fout("dest.png", std::ios::binary);
// TODO: handle errors.
fout << fin.rdbuf();