У меня есть функция в Jython, эта функция использует Popen для запуска другой программы, которая записывает XML-файл в свой стандартный вывод, который направляется в файл. Когда процесс завершен, я закрываю файл и вызываю другую функцию для его анализа. Я получаю кучу сообщений об ошибках, относящихся к доступу к закрытым файлам и / или неправильно отформатированным XML-файлам (которые выглядят нормально, когда я на них смотрю) во время анализа. Я думал, что output.close () может вернуться перед закрытием файла, и поэтому я добавил цикл, который ожидал, что output.closed будет истинным. Сначала это работало, но потом моя программа напечатала следующее
blasting
blasted
parsing
parsed
Extending genes found via genemark, 10.00% done
blasting
blasted
parsing
Exception in thread "_CouplerThread-7 (stdout)" Traceback (most recent call last):
File "/Users/mbsulli/jython/Lib/subprocess.py", line 675, in run
self.write_func(buf)
IOError: java.nio.channels.AsynchronousCloseException
[Fatal Error] 17_2_corr.blastp.xml:15902:63: XML document structures must start and end within the same entity.
Retry
blasting
blasted
parsing
Exception in thread "_CouplerThread-9 (stdout)" Traceback (most recent call last):
File "/Users/mbsulli/jython/Lib/subprocess.py", line 675, in run
self.write_func(buf)
IOError: java.nio.channels.ClosedChannelException
[Fatal Error] 17_2_corr.blastp.xml:15890:30: XML document structures must start and end within the same entity.
Retry
blasting
Я не уверен, что мои варианты отсюда. Правильно ли я думал, что xml не написан до того, как я его проанализировал? Если так, то кто я могу сделать, чтобы убедиться, что это так.
def parseBlast(fileName):
"""
A function for parsing XML blast output.
"""
print "parsing"
reader = XMLReaderFactory.createXMLReader()
reader.entityResolver = reader.contentHandler = BlastHandler()
reader.parse(fileName)
print "parsed"
return dict(map(lambda iteration: (iteration.query, iteration), reader.getContentHandler().iterations))
def cachedBlast(fileName, blastLocation, database, eValue, query, pipeline, remote = False, force = False):
"""
Performs a blast search using the blastp executable and database in blastLocation on
the query with the eValue. The result is an XML file saved to fileName. If fileName
already exists the search is skipped. If remote is true then the search is done remotely.
"""
if not os.path.isfile(fileName) or force:
output = open(fileName, "w")
command = [blastLocation + "/bin/blastp",
"-evalue", str(eValue),
"-outfmt", "5",
"-query", query]
if remote:
command += ["-remote",
"-db", database]
else:
command += ["-num_threads", str(Runtime.getRuntime().availableProcessors()),
"-db", database]
print "blasting"
blastProcess = subprocess.Popen(command,
stdout = output)
while blastProcess.poll() == None:
if pipeline.exception:
print "Stopping in blast"
blastProcess.kill()
output.close()
raise pipeline.exception
output.close()
while not output.closed:
pass
print "blasted"
try:
return parseBlast(fileName)
except SAXParseException:
print 'Retry'
return cachedBlast(fileName, blastLocation, database, eValue, query, pipeline, remote, True)