<类型 '异常.IOError'> [错误号 9] 错误的文件描述符

-2 投票
1 回答
3445 浏览
提问于 2025-04-18 10:26

下面的代码是一个程序的一部分,目的是从彭博终端获取数据,并把这些数据存入SQLite数据库。在我的32位Windows XP上运行得很好。但是在64位Windows 7上,它总是给我报错:“get_history.histfetch错误:[Errno 9] 错误的文件描述符”。虽然在64位操作系统上使用32位的Python应该没有问题。有时候,简单地退出程序再重新打开就能解决这个问题,但有时候就是不行。现在我对这个问题的原因感到很困惑。我查看了源代码,发现问题出现在调用“histfetch”时,但我完全不知道代码的哪个部分出错了。有没有人能帮帮我呢...? 我真的非常感谢。提前谢谢你们。

def run(self):
    try: pythoncom.CoInitializeEx(pythoncom.COINIT_APARTMENTTHREADED)
    except: pass
    while 1:
        if self.trigger:
            try: self.histfetch()
            except Exception,e:
                logging.error('get_history.histfetch error: %s %s' % (str(type(e)),str(e)))
                if self.errornotify != None:
                    self.errornotify('get_history error','%s %s' % ( str(type(e)), str(e) ) )
            self.trigger = 0
        if self.telomere: break
        time.sleep(0.5)

def histfetch(self):
    blpcon = win32com.client.gencache.EnsureDispatch('blpapicom.Session')
    blpcon.Start()
    dbcon = sqlite3.connect(self.dbfile)
    c = dbcon.cursor()
    fieldcodes = {}
    symcodes = {}
    trysleep(c,'select fid,field from fields')
    for fid,field in c.fetchall():
        # these are different types so this will be ok
        fieldcodes[fid] = field
        fieldcodes[field] = fid
    trysleep(c,'select sid,symbol from symbols')
    for sid,symbol in c.fetchall():
        symcodes[sid] = symbol
        symcodes[symbol] = sid
    for instr in self.instructions:
        if instr[1] != 'minute': continue
        sym,rollspec = instr[0],instr[2]
        print 'MINUTE',sym
        limits = []
        sid = getsid(sym,symcodes,dbcon,c)
        trysleep(c,'select min(epoch),max(epoch) from minute where sid=?',(sid,))
        try: mine,maxe = c.fetchone()
        except: mine,maxe = None,None
        print sym,'minute data limits',mine,maxe
        rr = getreqrange(mine,maxe)
        if rr == None: continue
        start,end = rr
        dstart = start.strftime('%Y%m%d')
        dend = end.strftime('%Y%m%d')
        try: # if rollspec is 'noroll', then this will fail and goto except-block
            ndaysbefore = int(rollspec)
            print 'hist fetch for %s, %i days' % (sym,ndaysbefore)
            rolldb.update_roll_db(blpcon,(sym,))
            names = rolldb.get_contract_range(sym,ndaysbefore)
        except: names = {sym:None}
        # sort alphabetically here so oldest always gets done first
        #  (at least within the decade)
        sorted_contracts = names.keys()
        sorted_contracts.sort()
        for contract in sorted_contracts:
            print 'partial fetch',contract,names[contract]
            if names[contract] == None:
                _start,_end = start,end
            else:
                da,db = names[contract]
                dc,dd = start,end
                try: _start,_end = get_overlap(da,db,dc,dd)
                except: continue # because get_overlap returning None cannot assign to tuple
            # localstart and end are for printing and logging
            localstart = _start.strftime('%Y/%m/%d %H:%M')
            localend = _end.strftime('%Y/%m/%d %H:%M')
            _start = datetime.utcfromtimestamp(time.mktime(_start.timetuple())).strftime(self.blpfmt)
            _end = datetime.utcfromtimestamp(time.mktime(_end.timetuple())).strftime(self.blpfmt)
            logging.debug('requesting intraday bars for %s (%s): %s to %s' % (sym,contract,localstart,localend))
            print 'start,end:',localstart,localend
            result = get_minute(blpcon,contract,_start,_end)
            if len(result) == 0:
                logging.error('warning: 0-length minute data fetch for %s,%s,%s' % (contract,_start,_end))
                continue
            event_count = len(result.values()[0])
            print event_count,'events returned'
            lap = time.clock()
            # todo: split up writes: no more than 5000 before commit (so other threads get a chance)
            #   100,000 rows is 13 seconds on my machine. 5000 should be 0.5 seconds.
            try:
                for i in range(event_count):
                    epoch = calendar.timegm(datetime.strptime(str(result['time'][i]),'%m/%d/%y %H:%M:%S').timetuple())
                    # this uses sid (from sym), NOT contract
                    row = (sid,epoch,result['open'][i],result['high'][i],result['low'][i],result['close'][i],result['volume'][i],result['numEvents'][i])
                    trysleep(c,'insert or ignore into minute (sid,epoch,open,high,low,close,volume,nevents) values (?,?,?,?,?,?,?,?)',row)
                dbcon.commit()
            except Exception,e:
                print 'ERROR',e,'iterating result object'
                logging.error(datetime.now().strftime() + ' error in get_history.histfetch writing DB')
                # todo: tray notify the error and log it
            lap = time.clock() - lap
            print 'database write of %i rows in %.2f seconds' % (event_count,lap)
            logging.debug(' -- minute bars %i rows (%.2f s)' % (event_count,lap))
    for instr in self.instructions:
        oldestdaily = datetime.now().replace(hour=0,minute=0,second=0,microsecond=0) - timedelta(self.dailyback)
        sym = instr[0]
        if instr[1] != 'daily': continue
        print 'DAILY',sym
        fields = instr[2]
        rollspec = instr[3]
        sid = getsid(sym,symcodes,dbcon,c)
        unionrange = None,None
        for f in fields:
            try: fid = fieldcodes[f]
            except:
                trysleep(c,'insert into fields (field) values (?)',(f,))
                trysleep(c,'select fid from fields where field=?',(f,))
                fid, = c.fetchone()
                dbcon.commit()
                fieldcodes[fid] = f
                fieldcodes[f] = fid
            trysleep(c,'select min(epoch),max(epoch) from daily where sid=? and fid=?',(sid,fid))
            mine,maxe = c.fetchone()
            if mine == None or maxe == None:
                unionrange = None
                break
            if unionrange == (None,None):
                unionrange = mine,maxe
            else:
                unionrange = max(mine,unionrange[0]),min(maxe,unionrange[1])
        print sym,'daily unionrange',unionrange
        yesterday = datetime.now().replace(hour=0,minute=0,second=0,microsecond=0) - timedelta(days=1)
        if unionrange == None:
            reqrange = oldestdaily,yesterday
        else:
            mine = datetime.fromordinal(unionrange[0])
            maxe = datetime.fromordinal(unionrange[1])
            print 'comparing',mine,maxe,oldestdaily,yesterday
            if oldestdaily < datetime.fromordinal(unionrange[0]): a = oldestdaily
            else: a = maxe
            reqrange = a,yesterday
        if reqrange[0] >= reqrange[1]:
            print 'skipping daily',sym,'because we\'re up to date'
            continue
        print 'daily request range',sym,reqrange,reqrange[0] > reqrange[1]
        try:
            ndaysbefore = int(rollspec) # exception if it's 'noroll'
            print 'hist fetch for %s, %i days' % (sym,ndaysbefore)
            rolldb.update_roll_db(blpcon,(sym,))
            names = rolldb.get_contract_range(sym,ndaysbefore,daily=True)
        except: names = {sym:None}
        # sort alphabetically here so oldest always gets done first
        #  (at least within the year)
        sorted_contracts = names.keys()
        sorted_contracts.sort()
        start,end = reqrange
        for contract in sorted_contracts:
            print 'partial fetch',contract,names[contract]
            if names[contract] == None:
                _start,_end = start,end
            else:
                da,db = names[contract]
                dc,dd = start,end
                try: _start,_end = get_overlap(da,db,dc,dd)
                except: continue # because get_overlap returning None cannot assign to tuple
            _start = _start.strftime('%Y%m%d')
            _end = _end.strftime('%Y%m%d')
            logging.info('daily bars for %s (%s), %s - %s' % (sym,contract,_start,_end))
            result = get_daily(blpcon,(contract,),fields,_start,_end)
            try: result = result[contract]
            except:
                print 'result doesn\'t contain requested symbol'
                logging.error("ERROR: symbol '%s' not in daily request result" % contract)
                # todo: log and alert error
                continue
            if not 'date' in result:
                print 'result has no date field'
                logging.error('ERROR: daily result has no date field')
                # todo: log and alert error
                continue
            keys = result.keys()
            keys.remove('date')
            logging.info(' -- %i days returned' % len(result['date']))
            for i in range(len(result['date'])):
                ordinal = datetime.fromtimestamp(int(result['date'][i])).toordinal()
                for k in keys:
                    trysleep(c,'insert or ignore into daily (sid,fid,epoch,value) values (?,?,?,?)',(sid,fieldcodes[k],ordinal,result[k][i]))
            dbcon.commit()

1 个回答

1

打印完整的错误追踪信息,而不仅仅是异常消息。错误追踪信息会告诉你异常是在哪里发生的,从而帮助你找到问题所在:

import traceback

...

    try: self.histfetch()
    except Exception,e:
        logging.error('get_history.histfetch error: %s %s' % (str(type(e)),str(e)))
        logging.error(traceback.format_exc())
        if self.errornotify != None:
            self.errornotify('get_history error','%s %s' % ( str(type(e)), str(e) ) )

更新:

根据上面的内容(或者类似的,关键是查看完整的错误追踪信息),你提到:

它说是和“print”函数有关。禁用所有“print”函数后,程序就正常运行了。

你在帖子中提到的 print 函数的写法只适用于 Python 2.x。如果你正在使用这个版本,可能运行你脚本的程序对 print 的定义不明确,你应该使用日志函数。否则,我看不出这些调用有什么问题(除非你是说只有某一个 print 出现了问题,那我需要看到具体的错误信息来帮助你识别——如果你想解决这个问题,可以把错误信息发出来)。如果你使用的是 Python 3.x,那么你必须使用 print(a, b, c, ...),具体可以查看 3.x 的文档。

撰写回答