Path: csiph.com!v102.xanadu-bbs.net!xanadu-bbs.net!feeder.erje.net!eu.feeder.erje.net!newsfeed.xs4all.nl!newsfeed4.news.xs4all.nl!xs4all!newsgate.cistron.nl!newsgate.news.xs4all.nl!post.news.xs4all.nl!not-for-mail Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.003 X-Spam-Evidence: '*H*': 0.99; '*S*': 0.00; 'else:': 0.03; 'exists.': 0.07; 'rename': 0.07; 'subject:file': 0.07; 'exist,': 0.09; 'iterate': 0.09; 'overwrite': 0.09; 'permission,': 0.09; 'try:': 0.09; 'def': 0.12; '"%s.%d"': 0.16; 'descriptor.': 0.16; 'e.errno': 0.16; 'errno': 0.16; 'fails.': 0.16; 'from:addr:cs': 0.16; 'from:addr:zip.com.au': 0.16; 'from:name:cameron simpson': 0.16; 'message-id:@cskk.homeip.net': 0.16; 'oserror': 0.16; 'simpson': 0.16; 'task.': 0.16; 'temp': 0.16; 'true:': 0.16; 'wrote:': 0.18; 'trying': 0.19; 'file,': 0.19; 'import': 0.22; 'header:User-Agent:1': 0.23; 'cheers,': 0.24; 'script': 0.25; 'least': 0.26; 'gets': 0.27; 'header:In-Reply-To:1': 0.27; 'function': 0.29; 'raise': 0.29; 'see,': 0.30; "i'm": 0.30; 'code': 0.31; 'catching': 0.31; 'file': 0.32; 'option': 0.32; 'run': 0.32; 'open': 0.33; 'used,': 0.33; 'could': 0.34; 'except': 0.35; 'problem.': 0.35; 'case,': 0.35; 'but': 0.35; 'there': 0.35; 'done': 0.36; 'charset:us-ascii': 0.36; 'example,': 0.37; 'too': 0.37; 'two': 0.37; 'skip:o 20': 0.38; 'to:addr:python-list': 0.38; 'files': 0.38; 'issue': 0.38; 'does': 0.39; 'to:addr:python.org': 0.39; 'matter': 0.61; 'course': 0.61; 'save': 0.62; 'content- disposition:inline': 0.62; 'name': 0.63; 'different': 0.65; 'received:113': 0.68; 'received:net.au': 0.68; 'therefore': 0.72; 'received:203': 0.74; 'collision': 0.84; 'forever.': 0.91; 'received:(may be forged)': 0.91; 'subject:Save': 0.91; 'mr.': 0.98 Date: Thu, 13 Mar 2014 09:19:25 +1100 From: Cameron Simpson To: python-list@python.org Subject: Re: Save to a file, but avoid overwriting an existing file MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.21 (2010-09-15) References: X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: Lines: 74 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1394664190 news.xs4all.nl 2959 [2001:888:2000:d::a6]:40823 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:68304 On 12Mar2014 13:29, zoom wrote: > I would like to assure that when writing to a file I do not > overwrite an existing file, but I'm unsure which is the best way to > approach to this problem. As I can see, there are at least two > possibilities: > > 1. I could use fd = os.open("x", os.O_WRONLY | os.O_CREAT | os.O_EXCL) > which will fail - if the file exists. However, I would prefer if the > program would try to save under different name in this case, instead > of discarding all the calculation done until now - but I' not too > well with catching exceptions. Others have menthions tempfile, though of course you have the same collision issue when you come to rename the temp file if you are keeping it. I would run with option 1 for your task. Just iterate until os.open succeeds. However, you need to distinuish _why_ an open fails. For example, if you were trying to make files in a directory to which you do not have write permission, or just a directory that did not exist, os.open would fail not matter what name you used, so your loop would run forever. Therefore you need to continue _only_ if you get EEXIST. Otherwise abort. So you'd have some code like this (totally untested): # at top of script import errno # where you make the file def open_new(primary_name): try: fd = os.open(primary_name, os.O_WRONLY | os.O_CREAT | os.O_EXCL) except OSError as e: if e.errno != errno.EEXIST: raise else: return primary_name, fd n = 1 while True: secondary_name = "%s.%d" % (primary_name, n) try: fd = os.open(secondary_name, os.O_WRONLY | os.O_CREAT | os.O_EXCL) except OSError as e: if e.errno != errno.EEXIST: raise else: return secondary_name, fd n += 1 # where you need the file path, fd = open_new("x") That gets you a function your can reuse which returns the file's name and the file descriptor. Cheers, -- Cameron Simpson Reason #173 to fear technology: o o o o o o ^|\ ^|^ v|^ v|v |/v |X| \| | /\ >\ /< >\ /< >\ /< >\ o> o o o o o o o \ x <\> <)> |\ /< >\ /< >\ /< >\ >> L Mr. email does the Macarena.