I am using the header zip.hpp (can be found here https://markand.bitbucket.io/libzip/index.html or here http://hg.markand.fr/libzip/file) to zip some files.
To remove the raw files afterwards, I use remove("myfile.txt").
Apparently, zip.hpp zips the files at the end of runtime, thus it cannot find the file and doesnt create a zip-folder. If I leave out remove("myfile.txt"), everything works fine, except for that I have a couple of files flying around that I only want to have in their zipped form.
Do you have any idea on how to force libzip to write the zip-files?
I would expect if I delete the archive-instance, it should force the creation, but apparently the libzip::Archive-class doesn't have a destructor (at least I can't find one and delete archive throws many errors)
My basic code looks like this:
#include <fstream>
#include <zip.h>
#include "lib/zip.hpp"
int main () {
libzip::Archive archive("output.zip", ZIP_CREATE);
std::ofstream outfile ("myfile.txt");
outfile << "Hello World\n";
outfile.close();
archive.add(libzip::source::file("myfile.txt"), "myfile2.txt");
// delete archive; // throws an error...
// remove("myfile.txt");
// if left out, output.zip gets created otherwise nothing is created
return 0;
}
The libzip::Archive will write its contents when it goes out of scope. So all you need to do is introduce an aditional scope before removing the file.
#include <fstream>
#include <zip.h>
#include "lib/zip.hpp"
int main () {
{ // Additional scope
libzip::Archive archive("output.zip", ZIP_CREATE);
std::ofstream outfile ("myfile.txt");
outfile << "Hello World\n";
outfile.close();
archive.add(libzip::source::file("myfile.txt"), "myfile2.txt");
} // Archive is written now.
remove("myfile.txt");
return 0;
}
Related
I have two similar methods that open a file identically, but process them and return values a bit differently, yet while the first method does that successfully, the second method, which is called after the first one, fails.
I have tried changing the path to this file, its extension, but I think I miss some important knowledge about ifstream.
vector<User> Database::createUserDatabase()
{
vector<User> users;
ifstream inputFile;
inputFile.open(pathToFile, ios::in);
//Some file processing
inputFile.close();
return users;
}
And that works perfectly, while
vector<User> Database::createBookDatabase()
{
vector<Book> books;
ifstream inputFile;
inputFile.open(pathToFile, ios::in);
//Some file processing
inputFile.close();
return books;
}
fails to end whenever I check if the file has been opened or not using
inputFile.is_open()
These functions are defined in class files Database.cpp, User.cpp, Book.cpp, which are correctly linked to the main.cpp with the following content:
#include <iostream>
#include <cstdlib>
#include <string>
#include <cstring>
#include <sstream>
#include <vector>
#include <fstream>
#include "../lib/Book.h"
#include "../lib/User.h"
#include "../lib/Database.h"
using namespace std;
int main()
{
Database userDatabase("../database/users.txt", "users");
Database bookDatabase("../database/lmsdb.txt", "books");
vector<User> users = userDatabase.createUserDatabase();
vector<Book> books = bookDatabase.createBookDatabase();
return 0;
}
Here are my Project directories
Using gdb debugger, I have confirmed that the file is not being opened at all. I assume that I did not close the files properly, but I have a little knowledge of C++ yet (been learning it for only a week or so).
Looking forward to see what you can suggest reading/researching, yet I really would like to see a straightforward solution to this problem.
I assume that I did not close the files properly, [..]
Yes, but that probably isn't the cause of the issue. The C++ way is to not close them explicitly. Due to RAII, the ifstream will close itself once it goes out of scope (i.e. when the enclosing function terminates).
There are many reasons why a file could fail to open, including:
It doesn't exist.
Trying to open a read-only file in write mode.
The file is in use by another process. (Maybe you have it opened in an editor?)
Insufficient privileges (e.g. due to the file being protected).
I have two files and in one I have created simple class :
#include <iostream>
#include <fstream>
#include <string>
#include <time.h>
#include <stdlib.h>
#include <conio.h>
#include <unistd.h>
class myclass{
protected:
int ima,imb,imc,tm;
fstream file;
public:
void creafile(string filename){
string dir;
dir = "txtfile/";
file.open((dir + filename).c_str(), ios::in | ios::out);
if(file.fail()){
// file.open(filename, ios::in | ios::out);
//if(file.fail())
cout<<"Error when creating the file"<<endl;
exit(1);
}
file.close();
}}
and my main file is called data.cpp and contain only this code:
using namespace std;
#include "mylib.h"
int main() {
myclass dat,hi;
dat.creafile("creatorfile.txt");
return 0;
}
My problem is that I always get an error when calling creafile Error when creating the file. To make a simpler test case, I also tried the following code:
file.open("myfile.txt");
if(!file){
cout<<"Error when creating the file"<<endl;
exit(1);
}
file.close();
However, it still gives the error Error when creating the file. I've tried using all flags ios::app ios::in ios::out etc but nothing changes. I have 500gb free space, and running Windows 7.
According to the reference, ios::in | ios::out std::ios_base::openmode configuration will an generate error if the file does not exist, so you won't create a new one with that.
I don't know why you're using the member std::fstream, createfile could just be a static function that does not change any object. You're even closing it afterwards! It would create a file using a local std::ofstream, open mode of which is std::ios_base::out, which will create the file:
std::ofstream ofs(dir + filename); // .c_str() not needed since C++11
Point 1: You cannot open to read if the file doesn't exist. Fortunately you probably don't want to. Simultaneously reading and writing the same file is problematic and almost always a bad idea. Until you know you have to read and write at the same time,
open the file for reading
read in the file
close the file.
edit the file in memory
open the file for writing
write out the file
close the file
If you have a really big file you can't store in memory,
open the file for reading
open a temporary file for writing
read in part of the file
edit the part you read
write the part you read to temporary
if more file, goto 3 (but don't use goto), else continue
close file
close temporary file
delete file
rename temporary file to file
Point 2: You have created the txtfile folder, but have you created it in the right place? Your development environment (include of conio.h suggests Visual Studio or antique) may not be running your program from where you think it is running.
Add this to your code in main:
char buf[4097]; // really big buffer
getcwd(buf, (int)sizeof(buf)); // get working directory
std::cout << buf << std::endl; // print the working directory
If the folder printed out is not where you made the txtfile folder, you can't open the file. If you want to automatically make the folder, read here: How to make a folder/directory
Point 3: exit(1); is a really big hammer. It is a nasty hammer. Read more here. Don't use it without a really, really good reason. In this case return is more than enough to get you out of the function, and if you add a return value to the function, main can test the return value to see if it should continue or return. Or you can throw an exception.
I'm new to C++ and I've just read <C++ Primer> 4ed. Now I want to implement a little program to help me manage some mp3 files in my computer.
I have a .txt file which includes all the names(part of the names actually) of the files which I want to move(not copy) to a new folder(in the same column). For example, "word" and "file" in the .txt and I want to move all the .mp3 files whose filename contain "word" or "file" to a new folder. Hope my discription is clear, Opps..
I know how to read the strings in .txt into a set<string> and traverse it, but I have no idea how to search and move a file in a folder. I just want to know what else should I learn so that I can implement this function. I read C++ Primer and still I can't do much thing, that's really sad...
To move a file in C++, you do not have to use external libraries like Boost.Filesystem, but you can use standard functionality.
There is the new filesystem API, which has a rename function:
#include <iostream>
#include <filesystem>
int main() {
try {
std::filesystem::rename("from.txt", "to.txt");
} catch (std::filesystem::filesystem_error& e) {
std::cout << e.what() << '\n';
}
return 0;
}
The drawback is to compile it, you need a recent C++17 compiler. (I tested it on gcc 8.0.1, and I also needed to link against -lstdc++fs).
But what should work on any C++ compiler today, is the old C API, which also provides rename (cstdio):
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cerrno>
int main() {
if(std::rename("from.txt", "to.txt") < 0) {
std::cout << strerror(errno) << '\n';
}
return 0;
}
But note that in both cases, the rename will fail if the source and destination files are not on the same filesystem. Then you will see an error like this:
filesystem error: cannot rename: Invalid cross-device link [from.txt] [/tmp/to.txt]
In that case, you can only make a copy and then remove the original file:
#include <fstream>
#include <iostream>
#include <ios>
#include <cstdio>
int main() {
std::ifstream in("from.txt", std::ios::in | std::ios::binary);
std::ofstream out("to.txt", std::ios::out | std::ios::binary);
out << in.rdbuf();
std::remove("from.txt");
}
Or with the new API:
#include <iostream>
#include <filesystem>
int main()
{
try {
std::filesystem::copy("from.txt", "to.txt");
std::filesystem::remove("from.txt");
} catch (std::filesystem::filesystem_error& e) {
std::cout << e.what() << '\n';
}
return 0;
}
Use rename() function to move a file
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
char oldname[] = "C:\\Users\\file_old.txt";
char newname[] = "C:\\Users\\New Folder\\file_new.txt";
/* Deletes the file if exists */
if (rename(oldname, newname) != 0)
perror("Error moving file");
else
cout << "File moved successfully";
return 0;
}
The only way for this to work only using std would be to read the file completely using a std::ifstream and then write it to the new location with a std::ofstream. This will however not remove the old file from disk. So basically you create a copy of the file. Its also much slower than a real move.
The optimal solution is to use OS specific APIs like win32 which e.g provide a MoveFile() function. Poco provides an platform independent abstraction of such APIs. See: http://www.appinf.com/docs/poco/Poco.File.html
Another way to move a file in Windows is using the MoveFile function as it is shown in the following code.
std::wstring oldPath = L"C:\\Users\\user1\\Desktop\\example\\text.txt";
std::wstring newPath = L"C:\\Users\\user1\\Desktop\\example1\\text.txt";
bool result = MoveFile(newPath.c_str(), oldPath.c_str());
if (result)
printf("File was moved!");
else
printf("File wasn't moved!");
under Windows run system call with batch commands:
system("move *text*.mp3 new_folder/");
system("move *word*.mp3 new_folder/");
Under Unix same with shell syntax.
I am just learning the very basic aspects of input/output streams, and can't seem to have my program read a text file. It gives me errors that indicate it is trying to read the .txt file as C++ code, while I am just using values in there to test my stream.
These are the contents of my included .txt file:
12345
Success
And here is the main program's code:
#include <fstream>
#include <iostream>
#include "C:\Users\Pavel\Desktop\strings.txt"
using namespace std;
int main (int nNumberOfArgs, char* pszArgs[])
{
ifstream in;
in.open("C:\Users\Pavel\Desktop\strings.txt");
int x;
string sz;
in << x << sz;
in.close();
return 0;
}
The first error message I receive is "expected unqualified-id before numeric constant" which tells me the program is attempting to compile the included file. How can I prevent this and have the text file read as intended?
Don't #include your .txt file. Includes are for source code. They textually insert the file into your code, as if you had actually copy-pasted it there. You shouldn't be #includeing a file you're opening with an ifstream.
Opening files on the filesystem at runtime doesn't require any mention of that file's name in the source code. (You could, for instance, ask the user for a filename, and then open it just fine!)
The case where you might #include data in your source would be if you wanted to have that data embedded into the executable of your program (and thus not rely on a file that was on the filesystem when running). But to do that, you have to format your file as a valid C++ data declaration. So it would not be a .txt file at that point.
For instance, in strings.cpp
#include <string>
// See http://stackoverflow.com/questions/1135841/c-multiline-string-literal
std::string myData =
"12345\n"
"Success";
Then in your main program:
#include <iostream>
#include <sstream>
#include "strings.cpp"
using namespace std;
int main (int nNumberOfArgs, char* pszArgs[])
{
istringstream in (myData);
int x;
// Note: "sz" is shorthand for "string terminated by zero"
// C++ std::strings are *not* null terminated, and can actually
// legally have embedded nulls. Unfortunately, C++ does
// have to deal with both kinds of strings (such as with the
// zero-terminated array of char*s passed as pszArgs...)
string str;
// Note: >> is the "extractor"
in >> x >> str;
// Note: << is the "inserter"
cout << x << "\n" << str << "\n";
return 0;
}
Generally speaking, just #include-ing a source file like this is not the way you want to do things. You'll quickly run into trouble if you do that in more than one file in your project (duplicate declarations of myData). So the usual trick is to separate things into header files and implementation files...including the headers as many times as you want, but only putting one copy of the implementation into your build process.
An #include directive works the same way regardless of the extension of the file being included - txt, h, no extension at all - it doesn't matter. How it works is the contents of the file are pasted into your source file by the preprocessor before that file is passed to the compiler. As far as the compiler is concerned, you might as well have just copied and pasted the contents yourself.
I have really strange problem. In Visual C++ express, I have very simple code, just:
#include <fstream>
using namespace std;
int main()
{
fstream file;
file.open("test.txt");
file<<"Hello";
file.close();
}
This same code works OK in my one project, but when I create now project and use this same lines of code, no file test.txt is created. Please, what is wrong?ยจ
EDIT: I expect to see test.txt in VS2008/project_name/debug - just like the first functional project does.
Canonical code to write to a file:
#include <fstream>
#include <iostream>
using namespace std;
int main() {
ofstream file;
file.open("test.txt");
if ( ! file.is_open() ) {
cerr << "open error\n";
}
if ( ! ( file << "Hello" ) ) {
cerr << "write error\n";
}
file.close();
}
Whenever you perform file I/O you must test every single operation, with the possible exception of closing a file, which it is not usually possible to recover from.
As for the file being created somewhere else - simply give it a weird name like mxyzptlk.txt and then search for it using Windows explorer.
Perhaps the executable is run in a different directory than it was before, making test.txt appear somewhere else. Try using an absolute path, such as "C:\\Users\\NoName\\Desktop\\test.txt" (The double backslashes are needed as escape characters in C strings).
fstream::open() takes two arguments: filename and mode. Since you are not providing the second, you may wish to check what the default argument in fstream is or provide ios_base::out yourself.
Furthermore, you may wish to check whether the file is open. It is possible that you do not have write permissions in the current working directory (where 'test.txt' will be written since you don't provide an absolute path). fstream provides the is_open() method as one way of checking this.
Lastly, think about indenting your code. While you only have a few lines there, code can soon become difficult to read without proper indentation. Sample code:
#include <fstream>
using namespace std;
int main()
{
fstream file;
file.open("test.txt", ios_base::out);
if (not file.is_open())
{
// Your error-handling code here
}
file << "Hello";
file.close();
}
You can use Process Monitor and filter on file access and your process to determine whether the open/write is succeeding and where on disk it's happening.
Theres two ways to fix this. Either do:
file.open("test.txt", ios::out)
#include <fstream>
using namespace std;
int main()
{
fstream file;
file.open("test.txt", ios::out);
file<<"Hello";
file.close();
}
Or you can create an ofstream instead of fstream.
#include <fstream>
using namespace std;
int main()
{
ofstream file;
file.open("test.txt");
file<<"Hello";
file.close();
}