यह निर्धारित करना कि क्या कोई निर्देशिका लिखने योग्य है


101

पायथन में सबसे अच्छा तरीका क्या होगा यह निर्धारित करने के लिए कि स्क्रिप्ट निष्पादित करने वाले उपयोगकर्ता के लिए एक निर्देशिका लेखन योग्य है या नहीं? चूँकि यह संभवतः ओएस मॉड्यूल का उपयोग करना शामिल होगा जिसका मुझे उल्लेख करना चाहिए कि मैं इसे * निक्स पर्यावरण के तहत चला रहा हूं।

जवाबों:


185

यद्यपि क्रिस्टोफ़ ने जो सुझाव दिया है वह एक अधिक पायथोनिक समाधान है, एक्सेस की जांच करने के लिए ओएस मॉड्यूल में os.access फ़ंक्शन है:

os.access('/path/to/folder', os.W_OK) # W_OK लिखने के लिए है, पढ़ने के लिए R_OK, आदि।


4
स्थिति के आधार पर, "क्षमा मांगने में आसान" पायथन में भी, सबसे अच्छा तरीका नहीं है। यह कभी-कभी "अनुमति माँगने" के लिए सलाह दी जाती है जैसा कि उल्लिखित os.access () विधि के साथ होता है, उदाहरण के लिए जब किसी त्रुटि को पकड़ने की संभावना अधिक होती है।
एमजेवी

53
यदि आप डायरेक्टरी में फाइल लिखना चाहते हैं तो केवल राइट बिट के लिए डायरेक्टरी का परीक्षण करना पर्याप्त नहीं है। यदि आप निर्देशिका में लिखना चाहते हैं, तो आपको निष्पादित बिट के लिए परीक्षण करना होगा। os.access ('/ path / to / folder', os.W_OK | os.X_OK) os.W_OK के साथ आप केवल निर्देशिका को हटा सकते हैं (और केवल अगर निर्देशिका खाली है)
fthinker

4
यह एक और os.access()है यह वास्तविक UID और GID का उपयोग करके जाँच करता है , प्रभावी नहीं है। यह SUID / SGID वातावरण में विचित्रता पैदा कर सकता है। ('लेकिन स्क्रिप्ट सेतु जड़ से चलती है, इसे फाइल में क्यों नहीं लिखा जा सकता?')
एलेक्सियो

5
शायद एक कार्यक्रम वास्तव में लिखने की आवश्यकता के बिना जानना चाहता है। यह सिर्फ गुण के अनुसार GUI के रूप और / या व्यवहार को बदलना चाह सकता है। उस मामले में मैं इसे केवल एक परीक्षण के रूप में एक फ़ाइल लिखने और हटाने के लिए pythonic नहीं मानूंगा।
बछसौ

1
बस एक विंडोज नेटवर्क शेयर पर परीक्षण किया गया। os.access(dirpath, os.W_OK | os.X_OK)अगर मैं कोई लेखन पहुँच नहीं है, तब भी सही है।
इमानिगीत

69

यह सुझाव अजीब लग सकता है, लेकिन एक सामान्य पायथन मुहावरा है

अनुमति के बजाय क्षमा मांगना आसान है

उस मुहावरे के बाद, कोई कह सकता है:

यदि आपको ऐसा करने की अनुमति नहीं है, तो प्रश्न में निर्देशिका को लिखने का प्रयास करें, और त्रुटि को पकड़ें।


5
+1 पायथन या नहीं, यह वास्तव में एक्सेस के लिए परीक्षण करने का सबसे विश्वसनीय तरीका है।
जॉन नोएलर

5
यह अन्य त्रुटियों का भी ध्यान रखता है जो डिस्क पर लिखते समय हो सकता है - उदाहरण के लिए कोई डिस्कस्पेस नहीं छोड़ा गया। यह कोशिश करने की शक्ति है .. आपको हर उस चीज़ को याद रखने की ज़रूरत नहीं है जो गलत हो सकती है
;;

4
धन्यवाद दोस्तों। गति के रूप में os.access के साथ जाने का निर्णय लिया, जो मैं यहां कर रहा हूं, उसमें एक महत्वपूर्ण कारक है, हालांकि मैं निश्चित रूप से गुणों को समझ सकता हूं "यह अनुमति की तुलना में माफी मांगना आसान है।" ;)
प्रबुद्ध

4
यह एक महान IDIO है ... मी - विशेष रूप से जब एक और मुहावरे के साथ युग्मित except: pass- इस तरह से आप हमेशा आशावादी हो सकते हैं और खुद को अत्यधिक सोच सकते हैं। / कटाक्ष। अब मैं अपने फाइल सिस्टम में हर निर्देशिका में कुछ लिखने की कोशिश क्यों करूँगा, जैसे कि लिखने योग्य स्थानों की सूची तैयार करने के लिए?
टॉमस गैंडर

4
शायद एक कार्यक्रम वास्तव में लिखने की आवश्यकता के बिना जानना चाहता है। यह सिर्फ गुण के अनुसार GUI के रूप और / या व्यवहार को बदलना चाह सकता है। उस मामले में मैं इसे केवल एक परीक्षण के रूप में एक फ़ाइल लिखने और हटाने के लिए pythonic नहीं मानूंगा।
बछसौ

19

tempfileमॉड्यूल का उपयोग कर मेरा समाधान :

import tempfile
import errno

def isWritable(path):
    try:
        testfile = tempfile.TemporaryFile(dir = path)
        testfile.close()
    except OSError as e:
        if e.errno == errno.EACCES:  # 13
            return False
        e.filename = path
        raise
    return True

अद्यतन: विंडोज पर फिर से कोड का परीक्षण करने के बाद मैं देखता हूं कि वास्तव में एक समस्या है जब वहां टेम्पोफाइल का उपयोग किया जाता है, तो समस्या को देखें । एक गैर-लेखन निर्देशिका के मामले में, कोड कई सेकंड के लिए लटका रहता है और अंत में एक फेंकता है IOError: [Errno 17] No usable temporary file name found। शायद यह वही है जो user2171842 देख रहा था? दुर्भाग्य से इस मुद्दे को अभी हल नहीं किया गया है इसलिए इसे संभालने के लिए, त्रुटि को भी पकड़ा जाना चाहिए:

    except (OSError, IOError) as e:
        if e.errno == errno.EACCES or e.errno == errno.EEXIST:  # 13, 17

इन मामलों में देरी अभी भी मौजूद है।


1
मुझे लगता है कि यह अस्थायी उपयोग करने वाला क्लीनर है क्योंकि यह सुनिश्चित नहीं करता है कि अवशिष्ट छोड़ दें।
टिड्डा

3
यह विधि काम नहीं कर रही है tempfile। यह केवल तभी काम करता है जब इसका कोई OSErrorअर्थ नहीं है कि इसे लिखने / हटाने की अनुमति है। अन्यथा यह नहीं होगा return Falseक्योंकि कोई त्रुटि वापस नहीं हुई है, और स्क्रिप्ट निष्पादित या बाहर निकलना जारी नहीं रखेगा। कुछ भी नहीं लौटाया जाता है। यह सिर्फ उस लाइन पर अटका हुआ है। हालाँकि, एक गैर-अस्थायी फ़ाइल जैसे कि खट्टम का उत्तर बनाने से अनुमति या इनकार करने पर काम होता है। मदद?

10

किसी के लिए उदाहरण खोजते हुए इस धागे के पार गिर गया। Google पर पहला परिणाम, बधाई!

लोग इस धागे में इसे करने के पायथोनिक तरीके के बारे में बात करते हैं, लेकिन कोई सरल कोड उदाहरण नहीं है? यहाँ आप जाते हैं, किसी और के लिए जो ठोकर खाता है:

import sys

filepath = 'C:\\path\\to\\your\\file.txt'

try:
    filehandle = open( filepath, 'w' )
except IOError:
    sys.exit( 'Unable to write to file ' + filepath )

filehandle.write("I am writing this text to the file\n")

यह लिखने के लिए एक फ़ाइलहैंडल खोलने का प्रयास करता है, और एक त्रुटि के साथ बाहर निकलता है यदि निर्दिष्ट फ़ाइल को नहीं लिखा जा सकता है: यह पढ़ना आसान है, और फ़ाइल पथ या निर्देशिका पर प्रीचेक करने के बजाय इसे करने का एक बेहतर तरीका है , क्योंकि यह दौड़ की स्थिति से बचा जाता है; उन मामलों में जहां फ़ाइल आपको प्रीचेक चलाने के समय के लिए अनिर्धारित हो जाती है, और जब आप वास्तव में फ़ाइल को लिखने का प्रयास करते हैं।


1
यह एक फ़ाइल पर लागू होता है, निर्देशिका नहीं जो ओपी ने पूछा है। आपके पास एक निर्देशिका में एक फ़ाइल हो सकती है और निर्देशिका को लिखने योग्य नहीं होना चाहिए लेकिन फ़ाइल ही है, फ़ाइल पहले से मौजूद होनी चाहिए। यह सिस्टम प्रशासन में महत्वपूर्ण हो सकता है जहाँ आप उदाहरण के लिए लॉग फाइल बना रहे हैं जिसे आप पहले से ही मौजूद हैं, लेकिन यह नहीं चाहते कि लोग टेम्प स्पेस के लिए लॉग डायरेक्टरी का उपयोग करें।
माइक एस

... और वास्तव में मैंने उसे वोट दिया, जो अब मुझे लगता है कि एक गलती थी। जातिगत स्थितियों के साथ, रोहाक के रूप में उल्लेख किए गए मुद्दे हैं। विभिन्न प्लेटफार्मों पर अन्य मुद्दे हैं जहां आप निर्देशिका का परीक्षण कर सकते हैं, और यह लिखने योग्य लगता है, लेकिन यह वास्तव में नहीं है। क्रॉस-प्लेटफ़ॉर्म निर्देशिका लेखन योग्य जाँच करना जितना दिखता है उससे अधिक कठिन है। इसलिए जब तक आप मुद्दों से अवगत होते हैं, यह एक अच्छी तकनीक हो सकती है। मैं इसे UNIX-y के नजरिए से भी देख रहा था, जो कि मेरी गलती है। कोई इस उत्तर को संपादित करता है ताकि मैं अपना -1 हटा सकूं।
माइक एस

मैंने इसे संपादित कर दिया है, यदि आप -1 को हटाना चाहते हैं :) और हाँ, क्रॉस-प्लेटफ़ॉर्म डायरेक्ट्री चेक अधिक जटिल हो सकते हैं, लेकिन आम तौर पर आप उस डायरेक्टरी में किसी फाइल को बनाना / लिखना चाहते हैं - किस स्थिति में मैंने जो उदाहरण दिया है वह अभी भी लागू होना चाहिए। यदि कुछ निर्देशिका अनुमति संबंधित समस्या सामने आती है, तो फ़ाइलहैंडल खोलने का प्रयास करते समय इसे अभी भी एक IOError फेंकना चाहिए।
रोहक

मैंने अपना नीचा हटा दिया। इस बारे में क्षमा करें, और आपके योगदान के लिए धन्यवाद।
माइक एस

कोई चिंता नहीं, जवाब देने वाले लोगों का हमेशा स्वागत किया जाता है!
Rohaq

9

यदि आप केवल फ़ाइल परमिट के बारे में परवाह os.access(path, os.W_OK)करते हैं , तो आपको वही करना चाहिए जो आप पूछते हैं। यदि आप इसके बजाय यह जानना चाहते हैं कि क्या आप निर्देशिका में लिख सकते हैं, तो लिखने के लिए open()एक परीक्षण फ़ाइल (यह पहले से मौजूद नहीं होनी चाहिए), किसी भी को पकड़ें और जांच करें IOError, और बाद में परीक्षण फ़ाइल को साफ करें।

आमतौर पर, TOCTOU हमलों से बचने के लिए (केवल एक समस्या अगर आपकी स्क्रिप्ट उन्नत विशेषाधिकार के साथ चलती है - suid या cgi या तो), आपको वास्तव में इन आगे के परीक्षणों पर भरोसा नहीं करना चाहिए, लेकिन निजी ड्रॉप करें open(), और उम्मीद करें IOError


7

मोड बिट्स की जाँच करें:

def isWritable(name):
  uid = os.geteuid()
  gid = os.getegid()
  s = os.stat(dirname)
  mode = s[stat.ST_MODE]
  return (
     ((s[stat.ST_UID] == uid) and (mode & stat.S_IWUSR)) or
     ((s[stat.ST_GID] == gid) and (mode & stat.S_IWGRP)) or
     (mode & stat.S_IWOTH)
     )

4
यह समाधान केवल यूनिक्स है।
ब्योर्न लिंडक्विस्ट

4

यहाँ कुछ ऐसा है जो मैंने क्रिस्टोफ़ीड के उत्तर के आधार पर बनाया है:

import os

def isWritable(directory):
    try:
        tmp_prefix = "write_tester";
        count = 0
        filename = os.path.join(directory, tmp_prefix)
        while(os.path.exists(filename)):
            filename = "{}.{}".format(os.path.join(directory, tmp_prefix),count)
            count = count + 1
        f = open(filename,"w")
        f.close()
        os.remove(filename)
        return True
    except Exception as e:
        #print "{}".format(e)
        return False

directory = "c:\\"
if (isWritable(directory)):
    print "directory is writable"
else:
    print "directory is not writable"

3
 if os.access(path_to_folder, os.W_OK) is not True:
            print("Folder not writable")
 else :
            print("Folder writable")

पहुँच के बारे में अधिक जानकारी यहाँ मिल सकती है


2
यह मूल रूप से मैक्स श्वाबकेह के उत्तर की एक प्रति है जिसके चारों ओर थोड़ा आवरण है। इसे एक त्वरित कॉपी पेस्ट बनाता है लेकिन एक बेहतर विचार यह होगा कि इसे मैक्स के मूल पद में जोड़ा जाए।
जोरिक स्लीजस्टर

1

मैं एक ही जरूरत में भाग गया, जबकि तर्क के माध्यम से एक तर्क जोड़ रहा था। निर्मित में type=FileType('w')मेरे लिए काम नहीं करेगा क्योंकि मैं एक निर्देशिका के लिए देख रहा था। मैंने अपनी समस्या को हल करने के लिए अपनी विधि लिखना समाप्त कर दिया। यहाँ argparse स्निपेट के साथ परिणाम है।

#! /usr/bin/env python
import os
import argparse

def writable_dir(dir):
    if os.access(dir, os.W_OK) and os.path.isdir(dir):
        return os.path.abspath(dir)
    else:
        raise argparse.ArgumentTypeError(dir + " is not writable or does not exist.")

parser = argparse.ArgumentParser()
parser.add_argument("-d","--dir", type=writable_dir(), default='/tmp/',
    help="Directory to use. Default: /tmp")
opts = parser.parse_args()

निम्नलिखित में यह परिणाम है:

$ python dir-test.py -h
usage: dir-test.py [-h] [-d DIR]

optional arguments:
  -h, --help         show this help message and exit
  -d DIR, --dir DIR  Directory to use. Default: /tmp

$ python dir-test.py -d /not/real
usage: dir-test.py [-h] [-d DIR]
dir-test.py: error: argument -d/--dir: /not/real is not writable or does not exist.

$ python dir-test.py -d ~

मैं वापस गया और प्रिंट opts.dir को अंत तक जोड़ा , और सब कुछ वांछित के रूप में कार्य करना प्रतीत होता है।


0

यदि आपको किसी अन्य उपयोगकर्ता की अनुमति की जांच करने की आवश्यकता है (हां, मुझे इस सवाल का विरोधाभास है, लेकिन किसी के लिए काम आ सकता है), आप इसे pwdमॉड्यूल के माध्यम से कर सकते हैं , और निर्देशिका के मोड बिट्स।

डिस्क्लेमर - विंडोज पर काम नहीं करता है, क्योंकि यह POSIX परमिशन मॉडल (और pwdमॉड्यूल वहां उपलब्ध नहीं है) का उपयोग नहीं करता है , जैसे - केवल * निक्स सिस्टम के लिए समाधान।

ध्यान दें कि एक निर्देशिका के लिए सभी 3 बिट्स सेट होते हैं - पढ़ें, लिखें और eXecute।
ठीक है, आर एक पूर्ण नहीं है, लेकिन w / o यह आप निर्देशिका में प्रविष्टियों को सूचीबद्ध नहीं कर सकते हैं (इसलिए आपको उनके नाम जानना होगा)। दूसरी ओर निष्पादन बिल्कुल आवश्यक है - w / o इसे उपयोगकर्ता फ़ाइल के इनोड को नहीं पढ़ सकता है; यहां तक ​​कि W होने पर भी, बिना X फाइलें बनाई या संशोधित नहीं की जा सकती हैं। इस लिंक पर अधिक विस्तृत विवरण।

अंत में, मोड statमॉड्यूल में उपलब्ध हैं , उनका विवरण इनोड (7) आदमी में है

नमूना कोड जाँच करने के लिए कैसे:

import pwd
import stat
import os

def check_user_dir(user, directory):
    dir_stat = os.stat(directory)

    user_id, group_id = pwd.getpwnam(user).pw_uid, pwd.getpwnam(user).pw_gid
    directory_mode = dir_stat[stat.ST_MODE]

    # use directory_mode as mask 
    if user_id == dir_stat[stat.ST_UID] and stat.S_IRWXU & directory_mode == stat.S_IRWXU:     # owner and has RWX
        return True
    elif group_id == dir_stat[stat.ST_GID] and stat.S_IRWXG & directory_mode == stat.S_IRWXG:  # in group & it has RWX
        return True
    elif stat.S_IRWXO & directory_mode == stat.S_IRWXO:                                        # everyone has RWX
        return True

    # no permissions
    return False
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.