2009-01-31 13 views
31

ठीक है, mkstemp POSIX में एक temp फ़ाइल बनाने का पसंदीदा तरीका है।एक temp फ़ाइल में std :: ofstream कैसे बनाएं?

लेकिन यह फ़ाइल खोलता है और int देता है, जो एक फ़ाइल वर्णनकर्ता है। उस से मैं केवल एक फ़ाइल बना सकता हूं, लेकिन std::ofstream नहीं, जिसे मैं सी ++ में पसंद करूंगा।

(जाहिर है, AIX और कुछ अन्य सिस्टम पर, आप एक std::ofstream एक फ़ाइल वर्णनकर्ता से बना सकते हैं, लेकिन मेरे संकलक की शिकायत जब मुझे लगता है कि कोशिश करते हैं।) मैं जानता हूँ कि मैं tmpnam के साथ एक अस्थायी फ़ाइल नाम मिल सकता है और उसके बाद अपने ही खोल इसके साथ ofstream, लेकिन वह दौड़ की स्थिति के कारण जाहिरा तौर पर असुरक्षित है, और चेतावनी एक संकलक में परिणाम (छ ++ v3.4 लिनक्स पर।):

warning: the use of `tmpnam' is dangerous, better use `mkstemp' 

तो, वहाँ किसी भी पोर्टेबल तरह से एक अस्थायी के लिए एक std::ofstream बनाने के लिए है फाइल?

उत्तर

10

मुझे लगता है कि यह काम करना चाहिए:

char *tmpname = strdup("/tmp/tmpfileXXXXXX"); 
    ofstream f; 
    int fd = mkstemp(tmpname); 
    f.attach(fd); 

संपादित करें: खैर, यह नहीं पोर्टेबल हो सकता है। आप देते हैं उपयोग नहीं कर सकते और न एक फ़ाइल वर्णनकर्ता से सीधे एक ofstream बना सकते हैं, तो आप ऐसा करने के लिए है: mkstemp पहले से ही आप के लिए फ़ाइल बनाता है

char *tmpname = strdup("/tmp/tmpfileXXXXXX"); 
mkstemp(tmpname); 
ofstream f(tmpname); 

के रूप में, रेस स्थिति नहीं होनी चाहिए यहाँ एक समस्या है।

+0

यह लिनक्स पर मेरे जी ++ v3.4.4 के साथ संकलित नहीं है। जाहिर है केवल कुछ प्लेटफार्मों में यह कार्य है। – Frank

+0

धन्यवाद! आपकी दूसरी विधि के लिए (mkstemp और फिर ऑफस्ट्रीम का उपयोग करके): क्या यह अभी भी I/O के संदर्भ में कुशल है? वह फाइल सिस्टम को दो बार एक्सेस करेगा, है ना? हमारी फाइल सिस्टम बहुत धीमी है और मुझे चिंता है कि यह उस पर एक अनावश्यक बोझ डालेगा। – Frank

+0

strdup पोर्टेबल नहीं है, या तो ... – Sol

16

मैं इस समारोह किया है:

#include <stdlib.h> 
#include <fstream> 
#include <iostream> 
#include <vector> 

std::string open_temp(std::string path, std::ofstream& f) { 
    path += "/XXXXXX"; 
    std::vector<char> dst_path(path.begin(), path.end()); 
    dst_path.push_back('\0'); 

    int fd = mkstemp(&dst_path[0]); 
    if(fd != -1) { 
     path.assign(dst_path.begin(), dst_path.end() - 1); 
     f.open(path.c_str(), 
       std::ios_base::trunc | std::ios_base::out); 
     close(fd); 
    } 
    return path; 
} 

int main() { 
    std::ofstream logfile; 
    open_temp("/tmp", logfile); 
    if(logfile.is_open()) { 
     logfile << "hello, dude" << std::endl; 
    } 
} 

आप शायद एक उचित फ़ाइल निर्माण मुखौटा के साथ umask कॉल करने के लिए यह सुनिश्चित करना चाहिये (मैं 0600 पसंद करेंगे) - mkstemp के लिए मैनपेज का कहना है कि फ़ाइल मोड निर्माण मुखौटा मानकीकृत नहीं है। यह इस तथ्य का उपयोग करता है कि mkstemp इसका उपयोग फ़ाइल नाम के तर्क को संशोधित करता है। इसलिए, हम इसे खोलते हैं और इसे खोले गए फ़ाइल को बंद करते हैं (इसलिए, इसे दो बार नहीं खोलने के लिए), उस फ़ाइल से जुड़े एक स्ट्रीम के साथ छोड़ा जा रहा है।

+0

मुझे आश्चर्य है कि std :: स्ट्रिंग को टेम्पलेट के रूप में उपयोग करना सुरक्षित है और (char *) dst.path.c_str() का उपयोग करना सुरक्षित है। Std :: स्ट्रिंग के सबसे समझदार कार्यान्वयन के लिए ठीक लगता है। – ididak

+0

ididak, यह सुरक्षित नहीं है। सी-स्ट्रिंग को इंगित करने योग्य नहीं है :) –

+0

सी ++ में एक std :: स्ट्रिंग में इसकी पहली प्रविष्टि को संदर्भित किया जा सकता है।इस प्रकार आप पास और somestring [0] कर सकते हैं; एक char * की उम्मीद एक समारोह के लिए। देखें: http://en.cppreference.com/w/cpp/string/basic_string –

2

हो सकता है कि यह काम करेगा:

char tmpname[256]; 
ofstream f; 
sprintf (tmpname, "/tmp/tmpfileXXXXXX"); 
int fd = mkstemp(tmpname); 
ofstream f(tmpname); 

मैं इसे करने की कोशिश नहीं की है, लेकिन आप देख सकते हैं।

0
char tempFileName[20]; // name only valid till next invocation of tempFileOpen 
ofstream tempFile; 
void tempFileOpen() 
{ 
    strcpy(tempFileName, "/tmp/XXXXXX"); 
    mkstemp(tempFileName); 
    tempFile.open(tempFileName); 
} 

यह कोड मेरे लिए जीसीसी/libstdC++ 6 4.8.4 और क्लैंग 3.9 के साथ भी काम करता है। अन्य उत्तरों के लिए भी धन्यवाद जो मेरे लिए सहायक थे।

संबंधित मुद्दे