如何将 InMemoryUploadedFile 对象复制到磁盘

Posted

技术标签:

【中文标题】如何将 InMemoryUploadedFile 对象复制到磁盘【英文标题】:How to copy InMemoryUploadedFile object to disk 【发布时间】:2011-04-11 18:36:19 【问题描述】:

我正在尝试捕获与表单一起发送的文件并在保存之前对其执行一些操作。所以我需要在临时目录中创建这个文件的副本,但我不知道如何访问它。 Shutil 的函数无法复制此文件,因为它没有路径。那么有没有办法以其他方式执行此操作?

我的代码:

    image = form.cleaned_data['image']
    temp = os.path.join(settings.PROJECT_PATH, 'tmp')
    sourceFile = image.name # without .name here it wasn't working either
    import shutil
    shutil.copy(sourceFile, temp)

这引发了:

Exception Type: IOError at / Exception Value: (2, 'No such file or directory')

还有调试:

#  (..)\views.py in function

  67. sourceFile = image.name
  68. import shutil
  69. shutil.copy2(sourceFile, temp) ...

# (..)\Python26\lib\shutil.py in copy2

  92. """Copy data and all stat info ("cp -p src dst").
  93.
  94. The destination may be a directory.
  95.
  96. """
  97. if os.path.isdir(dst):
  98. dst = os.path.join(dst, os.path.basename(src))  
  99. copyfile(src, dst) ... 
 100. copystat(src, dst)
 101.

▼ Local vars
Variable    Value
dst     
u'(..)\\tmp\\myfile.JPG'
src     
u'myfile.JPG'
# (..)\Python26\lib\shutil.py in copyfile

  45. """Copy data from src to dst"""
  46. if _samefile(src, dst):
  47. raise Error, "`%s` and `%s` are the same file" % (src, dst)
  48.
  49. fsrc = None
  50. fdst = None
  51. try:
  52. fsrc = open(src, 'rb') ...
  53. fdst = open(dst, 'wb')
  54. copyfileobj(fsrc, fdst)
  55. finally:
  56. if fdst:
  57. fdst.close()
  58. if fsrc:

▼ Local vars
Variable    Value
dst     
u'(..)\\tmp\\myfile.JPG'
fdst    
None
fsrc    
None
src     
u'myfile.JPG'

【问题讨论】:

【参考方案1】:

This 是类似的问题,它可能会有所帮助。

import os
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
from django.conf import settings

data = request.FILES['image'] # or self.files['image'] in your form

path = default_storage.save('tmp/somename.mp3', ContentFile(data.read()))
tmp_file = os.path.join(settings.MEDIA_ROOT, path)

【讨论】:

嗨,我认为硬编码“tmp/name.mp3”这将是跨平台路径中的一个问题,我尝试从 django.conf 导入设置 tmp = os 改进您的代码
。 path.join(settings.MEDIA_ROOT, "tmp", data.name) path = default_storage.save(tmp, ContentFile(data.read()))
当您在一个文件中上传许多 MB 时,问题就开始了。然后使用缓冲。像 while 循环中的 data.read(BUF_SIZE)。 Many/large 是一个相对量度,有许多变量(如内存量、磁盘大小、网络类型/速度等),但对于您可能会写入 @987654322 的大文件来说是的@. 您可以避免使用硬编码名称:FileField(upload_to='data-files-dir').generate_filename(None, data.name)【参考方案2】:

正如@Sławomir Lenart 所提到的,在上传大文件时,您不希望data.read() 堵塞系统内存。

来自Django docs:

循环使用 UploadedFile.chunks() 而不是使用 read() 确保 大文件不会占用系统内存

from django.core.files.storage import default_storage

filename = "whatever.xyz" # received file name
file_obj = request.data['file']

with default_storage.open('tmp/'+filename, 'wb+') as destination:
    for chunk in file_obj.chunks():
        destination.write(chunk)

这会将文件保存在MEDIA_ROOT/tmp/,就像您的default_storage 一样,除非另有说明。

【讨论】:

像这样我得到: FileNotFoundError: [Errno 2] 没有这样的文件或目录:'//.png'。想法? @Daviddd 该文件不在您认为的位置,并且与此代码无关。 @Emile Bergeron 我正在使用 django_storages 作为.default_storage。如何将文件写入媒体根目录?【参考方案3】:

这是使用 python 的mkstemp 的另一种方法:

### get the inmemory file
data = request.FILES.get('file') # get the file from the curl

### write the data to a temp file
tup = tempfile.mkstemp() # make a tmp file
f = os.fdopen(tup[0], 'w') # open the tmp file for writing
f.write(data.read()) # write the tmp file
f.close()

### return the path of the file
filepath = tup[1] # get the filepath
return filepath

【讨论】:

【参考方案4】:

您最好的做法是编写自定义上传处理程序。请参阅docs。如果添加“file_complete”处理程序,则无论有内存文件还是临时路径文件,都可以访问文件的内容。您还可以使用“receive_data_chunck”方法并在其中写入您的副本。

问候

【讨论】:

我使用了一段时间,直到上传了重复的名称并且 django 自动附加一个后缀以使文件名唯一。重命名的文件名在上传处理程序级别不可用。除此之外,这非常干净。【参考方案5】:

这就是我尝试在本地保存文件的方式

    file_object = request.FILES["document_file"]
    file_name = str(file_object)
    print(f'[INFO] File Name: file_name')
    with open(file_name, 'wb+') as f:
        for chunk in file_object.chunks():
            f.write(chunk)

【讨论】:

以上是关于如何将 InMemoryUploadedFile 对象复制到磁盘的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Django 中通过 PUT 请求处理文件上传?

FileField:强制使用 TemporaryUploadedFile

如何将thinkcmf导入eclipse

如何将CString转换成wstring

如何将Ios文件上传到

Qt如何将文字变成图片?