I want to create an output file in a threadsafe manner, and only if it does not exist. I want to use the file system for synchronization. With open() I would use the flags O_RWRONLY|O_CREAT|O_EXCL. Is there a way to do this in C++17 using the iostream or fstream ?
Prior to C++23 there is no way of opening an ofstream in exclusive mode.
Workaround: Use std::fopen which has this capability since C++17.
Example:
#include <cstdio>
// Mode "x" to make it fail if it already exists
std::FILE* fp = std::fopen("filename", "wx");
if(fp) {
// created exclusively
// work with fp ...
std::fclose(fp);
}
If you really want an ofstream you could create a helper function:
template<class Stream>
Stream open_exclusively(const std::string& filename) {
Stream rv;
if(std::FILE* fp = std::fopen(filename.c_str(), "wx"); fp) {
std::fclose(fp);
// overwrite the file that was created exclusively:
rv.open(filename);
} else {
// could not create file exclusivly, set the failbit in the stream:
rv.setstate(Stream::failbit);
}
return rv;
}
int main() {
auto os = open_exclusively<std::ofstream>("filename");
if(os) {
std::cout << "file created exclusively\n";
}
}
Demo
Edit:
Even though the above demo is compliant and works on all platforms I've tested it - wine (v6.16) can't handle it, so I opened a bug report at bugs.winehq.org. You can follow the progress here:
Standard library call fopen(..., "wx") not recognized - causes destruction of data
Edit 2:
The Wine bugfix ucrtbase: Add support for x mode in fopen is now included in Wine 6.20 so after upgrading to 6.20 (or later), this will be working as it should in Wine too.
From C++23 you can use the std::ios::noreplace openmode:
std::ofstream os("filename", std::ios::noreplace);
if(os) {
std::cout << "file created exclusively\n";
}
Related
I am using stm32H753xx and Cube FatFs library.
After our e-MMC has been soldered to our board, I want to bring-up.
My startup codes is here:
res = f_mount(&fat_fs, "0:", 0);
if (res != FR_OK) {
res = f_mkfs("", FM_ANY, 0, work, sizeof(work));
if (res != FR_OK) {
while(1) {
LOGGER_REPORT(FORMAT_REQUEST_FAILED);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
res = f_mount(&fat_fs, "0:", 0);
if (res != FR_OK) {
while(1) {
LOGGER_REPORT(FORMATTED_BUT_NOT_MOUNTED);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
}
I generally expect an error at mounting phase if bringing-up of a memory device is very first time and this implies why I made my software branch to f_mkfs functions if f_mount fails. But f_mount is returning FR_OK and software is skipping here.
Afterwards, I am doing some api calls to detect latest directory in the root and to create new one by giving a name in way that would be latest+1. ( latest is like ./70/ new one ./71/ anyway)
There are some api calls here f_opendir, f_readdir, f_closedir respectively and all of them returns succesfully but,
whenever I want to create new dir by calling fs_mkdir, it returns FR_NO_FILESYTEM.
If I call f_mkfs after f_mount above, a FAT is creating and software works but I can not call f_mkfs ile that and could not figure it out where I have to put this code to make it run only once at very initial bring-up of e-MMC.
I have recently started working in C++ and came across this situation when I have to create a directory while executing my code. The code is working fine when I have to create a single folder but it fails when I have to create another folder withing this newly created folder.
Suppose, I am in C: and want to store my file in C:/A/B/ .The following piece of code using mkdir() works fine if I have to store my file in C:/A/ but fails when I am adding another folder B.
Following is my code snippet:
#include <sys/stat.h>
#include <string>
using namespace std;
int main()
{
string stringpath = "C:/A/B/";
int status = mkdir(stringpath.c_str(),0777);
if(status!=0)
{
//.....
}
else
{
//....
}
}
Can someone help me in creating this directory where I can have any number of folders inside the parent directory? (P.S:I have added the header files sys/stat.h,iostream and string)
This is how you do it in C++17:
#include <filesystem>
namespace fs = std::filesystem;
fs::create_directories("./a/b/c")
mkdir() creates only the last component of the specified path. In your example, it will create only B. If any of the parent directories do not exist (ie, if A does not exist), the function fails with ENOENT. You need to split up the path and call mkdir() for every intermediate directory in the path, ignoring EEXIST errors as you go.
status = mkdir("C:/A/", 0777);
if ((status < 0) && (errno != EEXIST)) ...
status = mkdir("C:/A/B/", 0777);
if ((status < 0) && (errno != EEXIST)) ...
If you don't want to handle this manually, use a wrapper that handles it for you, such as Boost's create_directories() function:
bool create_directories(const path& p);
bool create_directories(const path& p, system::error_code& ec);
Effects: Establishes the postcondition by calling create_directory() for any element of p that does not exist.
Postcondition: is_directory(p)
Returns: true if a new directory was created, otherwise false.
Throws: As specified in Error reporting.
Complexity: O(n+1)where n is the number of elements of p that do not exist.
You can call the following:
string stringpath = "C:/A/B/";
int status = mkdir(stringpath.c_str(),0777);
If
C:/A/ directory exists. If its not exists, then do the following:
string stringpath = "C:/A/";
int status = mkdir(stringpath.c_str(),0777);
stringpath = "C:/A/B/";
int status = mkdir(stringpath.c_str(),0777);
In C++11 you can use the experimental functios:
#include <experimental/filesystem>
...
std::stringstream bufH;
bufH << dirName << fName;
if (!std::experimental::filesystem::exists(bufH.str()))
{
std::experimental::filesystem::create_directories(bufH.str());
}
Try the octal flag 7777 like this to have all the rights necessary to create this folder.
int status = mkdir(stringpath.c_str(), 7777);
Or do a chmod in the A folder like that :
chmod -r 7777 *
I am trying to test run the first example in curlpp and I am getting the error "Undefined symbol: _curl_easy_setopt". I have an idea that this is a problem with how I have tried linking the library. Below is my methodology.
header search paths -> for both debug and release -> (I typed) /usr/local/include
library search paths -> for both debug and release -> (I typed) /usr/local/lib
other linker flags -> for both debug and release -> (I typed) -lcurlpp
I ran the the example with an API url I have used in python successfully in place of "example.com".This is a picture of the full error. Thank you!`
#include <string>
#include <sstream>
#include <iostream>
#include <curlpp/cURLpp.hpp>
#include <curlpp/Easy.hpp>
#include <curlpp/Options.hpp>
namespace
{
const long MyPort = 80;
}
/**
* This example is made to show you how you can use the Options.
*/
int main(int, char **)
{
try
{
curlpp::Cleanup myCleanup;
// First easy example.
{
// The first easiest example is to retreive the content of
// a web page and put it in a stream.
std::cout << curlpp::options::Url("https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=VSLR&frequency=5min&outputsize=full&datatype=json&apikey=IGDV8B3MO9GQ9R35");
// You don't need to use just the standard outputs. You
// can use any stream:
std::ostringstream os;
os << curlpp::options::Url("https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=VSLR&frequency=5min&outputsize=full&datatype=json&apikey=IGDV8B3MO9GQ9R35");
}
// More elaborate example.
{
// What the previous example done there was simply
// to create a curlpp::Easy class, which is the basic
// object in cURLpp, and then set the Url option.
// curlpp::options classes are the primitives that allow to specify
// values to the requests.
curlpp::options::Url myUrl(std::string("https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=VSLR&frequency=5min&outputsize=full&datatype=json&apikey=IGDV8B3MO9GQ9R35"));
curlpp::Easy myRequest;
myRequest.setOpt(myUrl);
// Now that all the options we wanted to set are there, we need to
// actually do the request. the "perform" method does actually that.
// With that call, the request will be done and the content of that URL
// will be printed in std::cout (which is the default).
myRequest.perform();
// If we wanted to put the content of the URL within a string stream
// (or any type of std::ostream, for that matter), like the first example,
// we would use the WriteStrem option like this:
std::ostringstream os;
curlpp::options::WriteStream ws(&os);
myRequest.setOpt(ws);
myRequest.perform();
// There is some shorcut within curlpp that allow you to write shorter code
// like this:
os << myRequest;
// That would do exactly what the previous code was doing.
}
// Creation of the URL option.
curlpp::options::Url myUrl(std::string("https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=VSLR&frequency=5min&outputsize=full&datatype=json&apikey=IGDV8B3MO9GQ9R35"));
// Copy construct from the other URL.
curlpp::options::Url myUrl2(myUrl);
// Creation of the port option.
curlpp::options::Port myPort(MyPort);
// Creation of the request.
curlpp::Easy myRequest;
// Creation of an option that contain a copy of the URL option.
curlpp::OptionBase *mytest = myUrl.clone();
myRequest.setOpt(*mytest);
// You can reuse the base option for other type of option
// and set the option to the request. but first, don't forget
// to delete the previous memory. You can delete it since the
// option is internally duplicated for the request.
delete mytest;
mytest = myPort.clone();
myRequest.setOpt(*mytest);
delete mytest;
// You can clone an option directly to the same type of
// option.
curlpp::options::Url *myUrl3 = myUrl.clone();
myRequest.setOpt(myUrl3);
// Now myUrl3 is owned by the request we will NOT use
// it anymore.
// You don't need to declare an option if you just want
// to use it once.
myRequest.setOpt(curlpp::options::Url("https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=VSLR&frequency=5min&outputsize=full&datatype=json&apikey=IGDV8B3MO9GQ9R35"));
// Note that the previous line wasn't really efficient
// because we create the option, this option is duplicated
// for the request and then the option destructor is called.
// You can use this instead:
myRequest.setOpt(new curlpp::options::Url("https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=VSLR&frequency=5min&outputsize=full&datatype=json&apikey=IGDV8B3MO9GQ9R35"));
// Note that with this the request will use directly this
// instance we just created. Be aware that if you pass an
// Option pointer to the setOpt function, it will consider
// the instance has its own instance. The Option instance
// will be deleted when the request will be deleted, so
// don't use the instance further in your code.
// Doing the previous line is efficient as this:
myRequest.setOpt(myUrl.clone());
// You can retreive the value of a specific option.
std::cout << myUrl2.getValue() << std::endl;
// Perform the transaction with the options set.
myRequest.perform();
}
catch( curlpp::RuntimeError &e )
{
std::cout << e.what() << std::endl;
}
catch( curlpp::LogicError &e )
{
std::cout << e.what() << std::endl;
}
return 0;
}
The missing symbol _curl_easy_setopt and the curlpp homepage tells me that curlpp is a C++ wrapper around the C library libcurl.
You therefore need to add -lcurl to link with that library too when compiling.
I am experimenting on webrtc, My goal is to store remote audio stream as a local file without using the media server, I am aware of aecdump but I don't find proper method or blog to unzip in iOS.
I am using googleWebrtc native framework.
Thanks.
Yes First to get the IOS directory path you must have to create your own objective c file.
my_ios_wav.mm
#import <Foundation/Foundation.h>
#include <string.h>
#import "sdk/objc/helpers/NSString+StdString.h"
#include "rtc_base/checks.h"
namespace webrtc{
std::string myIOSPath() {
#autoreleasepool {
NSString* tempDir = NSTemporaryDirectory();
if (tempDir == nil)
tempDir = #"/tmp";
return [NSString stdStringForString:tempDir];
}
}
}
After that create a static function in the class you have data that you want to record.
static webrtc::WavWriter* my_funtion()
{
const std::string outfilewav = webrtc::myIOSPath() + "wavtest1.wav";
static webrtc::WavWriter *my_wav_pointer(new
webrtc::WavWriter(outfilewav, 48000,1,webrtc::WavFile::SampleFormat::kInt16));
return my_wav_pointer;
}
After that call this static function where you want to pass the data to wav file for recording like:
my_funtion()->WriteSamples(audio_frame->data(), number_of_frames);
I am trying to save some files on micro SDCard. To check the availability of SDCard, I am using the following method;
private boolean isSdCardReady() {
Enumeration e = FileSystemRegistry.listRoots();
while (e.hasMoreElements()) {
if (e.nextElement().toString().equalsIgnoreCase("sdcard/")) {
return true;
}
}
return false;
}
Even if this method returns true, when I try to save files, it gives exception net.rim.device.api.io.file.FileIOException: File system is not ready.
What does this means? If SDCard is not available, then why its listed in FileSystemRegistry.listRoots()?
How can I make sure that SDCard is available for writing?
My development environment:
BlackBerry JDE Eclipse Plugin 1.5.0
BlackBerry OS 4.5
BlackBerry Bold with a 3G card
Usually I had this error when I tried to access SD card on device restart. You have to postpone all operations in app until startup finished:
while (ApplicationManager.getApplicationManager().inStartup()) {
try {
Thread.sleep(500);
} catch (InterruptedException ignored) {
}
}
I remember one more possible cause mentioned here. You have to close all streams after using.
Solved the problem. I was looking for "sdcard" while rootsEnum.nextElement().toString(); returns "SDCard". Yeah, its case sensitive. Now, instead of using hard-coded "SDCard", I've changed the above method to the following;
private static String getSdCardRootDir() {
Enumeration rootsEnum = FileSystemRegistry.listRoots();
while (rootsEnum.hasMoreElements()) {
String rootDir = rootsEnum.nextElement().toString();
if (rootDir.equalsIgnoreCase("sdcard/")) {
return "file:///" + rootDir;
}
}
return null;
}
Using this, I got the root directory in its system defined case.