app/django/core/files/base.py
changeset 323 ff1a9aa48cfd
equal deleted inserted replaced
322:6641e941ef1e 323:ff1a9aa48cfd
       
     1 import os
       
     2 
       
     3 from django.utils.encoding import smart_str, smart_unicode
       
     4 
       
     5 try:
       
     6     from cStringIO import StringIO
       
     7 except ImportError:
       
     8     from StringIO import StringIO
       
     9 
       
    10 class File(object):
       
    11     DEFAULT_CHUNK_SIZE = 64 * 2**10
       
    12 
       
    13     def __init__(self, file):
       
    14         self.file = file
       
    15         self._name = file.name
       
    16         self._mode = file.mode
       
    17         self._closed = False
       
    18 
       
    19     def __str__(self):
       
    20         return smart_str(self.name or '')
       
    21 
       
    22     def __unicode__(self):
       
    23         return smart_unicode(self.name or u'')
       
    24 
       
    25     def __repr__(self):
       
    26         return "<%s: %s>" % (self.__class__.__name__, self or "None")
       
    27 
       
    28     def __nonzero__(self):
       
    29         return not not self.name
       
    30 
       
    31     def __len__(self):
       
    32         return self.size
       
    33 
       
    34     def _get_name(self):
       
    35         return self._name
       
    36     name = property(_get_name)
       
    37 
       
    38     def _get_mode(self):
       
    39         return self._mode
       
    40     mode = property(_get_mode)
       
    41 
       
    42     def _get_closed(self):
       
    43         return self._closed
       
    44     closed = property(_get_closed)
       
    45 
       
    46     def _get_size(self):
       
    47         if not hasattr(self, '_size'):
       
    48             if hasattr(self.file, 'size'):
       
    49                 self._size = self.file.size
       
    50             elif os.path.exists(self.file.name):
       
    51                 self._size = os.path.getsize(self.file.name)
       
    52             else:
       
    53                 raise AttributeError("Unable to determine the file's size.")
       
    54         return self._size
       
    55 
       
    56     def _set_size(self, size):
       
    57         self._size = size
       
    58 
       
    59     size = property(_get_size, _set_size)
       
    60 
       
    61     def chunks(self, chunk_size=None):
       
    62         """
       
    63         Read the file and yield chucks of ``chunk_size`` bytes (defaults to
       
    64         ``UploadedFile.DEFAULT_CHUNK_SIZE``).
       
    65         """
       
    66         if not chunk_size:
       
    67             chunk_size = self.__class__.DEFAULT_CHUNK_SIZE
       
    68 
       
    69         if hasattr(self, 'seek'):
       
    70             self.seek(0)
       
    71         # Assume the pointer is at zero...
       
    72         counter = self.size
       
    73 
       
    74         while counter > 0:
       
    75             yield self.read(chunk_size)
       
    76             counter -= chunk_size
       
    77 
       
    78     def multiple_chunks(self, chunk_size=None):
       
    79         """
       
    80         Returns ``True`` if you can expect multiple chunks.
       
    81 
       
    82         NB: If a particular file representation is in memory, subclasses should
       
    83         always return ``False`` -- there's no good reason to read from memory in
       
    84         chunks.
       
    85         """
       
    86         if not chunk_size:
       
    87             chunk_size = self.DEFAULT_CHUNK_SIZE
       
    88         return self.size > chunk_size
       
    89 
       
    90     def xreadlines(self):
       
    91         return iter(self)
       
    92 
       
    93     def readlines(self):
       
    94         return list(self.xreadlines())
       
    95 
       
    96     def __iter__(self):
       
    97         # Iterate over this file-like object by newlines
       
    98         buffer_ = None
       
    99         for chunk in self.chunks():
       
   100             chunk_buffer = StringIO(chunk)
       
   101 
       
   102             for line in chunk_buffer:
       
   103                 if buffer_:
       
   104                     line = buffer_ + line
       
   105                     buffer_ = None
       
   106 
       
   107                 # If this is the end of a line, yield
       
   108                 # otherwise, wait for the next round
       
   109                 if line[-1] in ('\n', '\r'):
       
   110                     yield line
       
   111                 else:
       
   112                     buffer_ = line
       
   113 
       
   114         if buffer_ is not None:
       
   115             yield buffer_
       
   116 
       
   117     def open(self, mode=None):
       
   118         if not self.closed:
       
   119             self.seek(0)
       
   120         elif os.path.exists(self.file.name):
       
   121             self.file = open(self.file.name, mode or self.file.mode)
       
   122         else:
       
   123             raise ValueError("The file cannot be reopened.")
       
   124 
       
   125     def seek(self, position):
       
   126         self.file.seek(position)
       
   127 
       
   128     def tell(self):
       
   129         return self.file.tell()
       
   130 
       
   131     def read(self, num_bytes=None):
       
   132         if num_bytes is None:
       
   133             return self.file.read()
       
   134         return self.file.read(num_bytes)
       
   135 
       
   136     def write(self, content):
       
   137         if not self.mode.startswith('w'):
       
   138             raise IOError("File was not opened with write access.")
       
   139         self.file.write(content)
       
   140 
       
   141     def flush(self):
       
   142         if not self.mode.startswith('w'):
       
   143             raise IOError("File was not opened with write access.")
       
   144         self.file.flush()
       
   145 
       
   146     def close(self):
       
   147         self.file.close()
       
   148         self._closed = True
       
   149 
       
   150 class ContentFile(File):
       
   151     """
       
   152     A File-like object that takes just raw content, rather than an actual file.
       
   153     """
       
   154     def __init__(self, content):
       
   155         self.file = StringIO(content or '')
       
   156         self.size = len(content or '')
       
   157         self.file.seek(0)
       
   158         self._closed = False
       
   159 
       
   160     def __str__(self):
       
   161         return 'Raw content'
       
   162 
       
   163     def __nonzero__(self):
       
   164         return True
       
   165 
       
   166     def open(self, mode=None):
       
   167         if self._closed:
       
   168             self._closed = False
       
   169         self.seek(0)