2015-09-14 176 views
0

这是我的第一篇文章。我一直在进行python编程,最近正在开发一个多线程下载器。但问题是我的文件(jpg是我的目标)被损坏。另外随着followinf输入:http://www.aumathletics.com/images_web/headerAUMLogo.jpgPython简单的多线程下载文件损坏

它显示错误

,而与输入: http://www.nasa.gov/images/content/607800main_kepler1200_1600-1200.jpg

的文件被损坏。

下面是代码: -

import os, sys, requests 
import threading 
import urllib2 
import time 

URL = sys.argv[1] 

def buildRange(value, numsplits): 
    lst = [] 
    for i in range(numsplits): 
    if i == 0: 
     lst.append('%s-%s' % (i, int(round(1 + i * value/(numsplits*1.0) + value/(numsplits*1.0)-1, 0)))) 
    else: 
     lst.append('%s-%s' % (int(round(1 + i * value/(numsplits*1.0),0)), int(round(1 + i * value/(numsplits*1.0) + value/(numsplits*1.0)-1, 0)))) 
return lst 

def main(url=None, splitBy=5): 
    start_time = time.time() 
    if not url: 
     print "Please Enter some url to begin download." 
     return 

fileName = "image.jpg" 
sizeInBytes = requests.head(url, headers={'Accept-Encoding': 'identity'}).headers.get('content-length', None) 
print "%s bytes to download." % sizeInBytes 
if not sizeInBytes: 
    print "Size cannot be determined." 
    return 

dataDict = {} 

# split total num bytes into ranges 
ranges = buildRange(int(sizeInBytes), splitBy) 

def downloadChunk(idx, irange): 
    req = urllib2.Request(url) 
    req.headers['Range'] = 'bytes={}'.format(irange) 
    dataDict[idx] = urllib2.urlopen(req).read() 

# create one downloading thread per chunk 
downloaders = [ 
    threading.Thread(
     target=downloadChunk, 
     args=(idx, irange), 
    ) 
    for idx,irange in enumerate(ranges) 
    ] 

# start threads, let run in parallel, wait for all to finish 
for th in downloaders: 
    th.start() 
for th in downloaders: 
    th.join() 



print 'done: got {} chunks, total {} bytes'.format(
    len(dataDict), sum((
     len(chunk) for chunk in dataDict.values() 
    )) 
) 

print "--- %s seconds ---" % str(time.time() - start_time) 

if os.path.exists(fileName): 
    os.remove(fileName) 



# reassemble file in correct order 
with open(fileName, 'w') as fh: 

    for _idx,chunk in sorted(dataDict.iteritems()): 
     fh.write(chunk) 

print "Finished Writing file %s" % fileName 
print 'file size {} bytes'.format(os.path.getsize(fileName)) 

if __name__ == '__main__': 
    main(URL) 

这里的缺口可能是错了,所以这里是代码引擎收录(点)的COM/wGEkp878

我会很感激,如果有人能指出错误

编辑:由人提议

def buildRange(value, numsplits): 
    lst = [] 
    for i in range(numsplits): 
     first = i if i == 0 else buildRange().start(i, value, numsplits) 
     second = buildRange().end(i, value, numsplits) 
     lst.append("{}-{}".format(first, second)) 
    return lst 

谁能告诉我锄保持part1 part2等名称下载的零件文件等

+0

作为第一个猜它看起来你有更为复杂,它的buildRange功能应该是,这也可能是你的问题。更重要的是,我很抱歉,这不是你的问题的答案,但多线程下载这样的下载几乎肯定会花费更多的时间,而不是在单个请求中进行。原因是尽管您的所有数据都在同一时间下载,但您仍然受限于带宽,现在您还有许多其他事情正在进行。虽然这是一个很酷的实验,但绝对值得完成。 –

+0

你能告诉我如何存储作为part 1 2 3 4 etc下载的零件文件吗? – AKM

+0

你原来的构建范围似乎工作,但新的做得好得多。真正的问题似乎是额外的新行字符被添加!每遇到'\ n',在它之前插入一个额外的0x0D。 –

回答

0

事实证明,文件必须以二进制模式打开,'wb'而不是'w'。如果用'w'打开,会写入一堆额外的字符。这与derpy windows与linux新行语义有关。如果你使用'wb',它会准确地写入你放入文件的内容。

编辑: 如果要存储个人文件部分可以改变

# reassemble file in correct order 
with open(fileName, 'w') as fh: 
    for _idx,chunk in sorted(dataDict.iteritems()): 
     fh.write(chunk) 

print "Finished Writing file %s" % fileName 
print 'file size {} bytes'.format(os.path.getsize(fileName)) 

# reassemble file in correct order 
for _idx,chunk in sorted(dataDict.iteritems()): 
    with open(fileName + str(".part-") + str(_idx), 'wb') as fh: 
     fh.write(chunk) 

print "Finished Writing file %s" % fileName 
#print 'file size {} bytes'.format(os.path.getsize(fileName)) 
+0

仍然没有得到正确的文件 102331字节下载。 做到:有5块,共102331个字节 ---1.9279999733秒--- 写完文件image.jpg的 文件大小102948个字节 – AKM

+0

我试图在你提到的几个文件,它肯定写入正确的信息到文件。从字面上看,所有需要更改的行是 ,其中open(fileName,'w')为fh: 至 与open(fileName,'wb')为fh: –

+0

谢谢..可能你还告诉我,我怎么能保持部分文件太 – AKM