2014-07-21 37 views
4

我有一個非常大的csv文件,我無法在內存中完全加載。所以我想逐塊讀取它,將它轉換爲numpy數組,然後再做一些處理。在python中讀取大的csv文件的行

我已經籤: Lazy Method for Reading Big File in Python?

但這裏的問題是,這是一個正常的讀者,我無法找到csvReader指定大小的任何選項。

此外,因爲我想將行轉換爲numpy數組,我不想讀取任何行的一半,因此,而不是指定大小,我想要的東西,我可以在讀者中指定「no行」。

是否有任何內置功能或簡單的方法來做到這一點。

+0

你看過http://pandas.pydata.org/嗎?我自己並沒有使用熊貓,但我認爲這對於這類事情很有用。 –

+1

除了在用於創建閱讀器的文件對象上設置'buffering'參數還有更多嗎?所有的Python對象都不需要進一步的努力就可以支持懶惰評估,你只是想確保文件不會試圖將整個內容拉入內存。 –

回答

2

csv.reader不會將整個文件讀入內存。當您遍歷reader對象時,它會逐行地逐行遍歷文件。因此,您可以像平常一樣使用reader,但在讀取後您的迭代中可以使用break,但需要閱讀的行數很多。你可以在C-code used to implement the reader object看到這個。

Initializer for the reader objecT: 
static PyObject * 
csv_reader(PyObject *module, PyObject *args, PyObject *keyword_args) 
{ 
    PyObject * iterator, * dialect = NULL; 
    ReaderObj * self = PyObject_GC_New(ReaderObj, &Reader_Type); 

    if (!self) 
     return NULL; 

    self->dialect = NULL; 
    self->fields = NULL; 
    self->input_iter = NULL; 
    self->field = NULL; 
    // stuff we dont care about here 
    // ... 
    self->input_iter = PyObject_GetIter(iterator); // here we save the iterator (file object) we passed in 
    if (self->input_iter == NULL) { 
     PyErr_SetString(PyExc_TypeError, 
         "argument 1 must be an iterator"); 
     Py_DECREF(self); 
     return NULL; 
    } 

static PyObject * 
Reader_iternext(ReaderObj *self) // This is what gets called when you call `next(reader_obj)` (which is what a for loop does internally) 
{ 
    PyObject *fields = NULL; 
    Py_UCS4 c; 
    Py_ssize_t pos, linelen; 
    unsigned int kind; 
    void *data; 
    PyObject *lineobj; 

    if (parse_reset(self) < 0) 
     return NULL; 
    do { 
     lineobj = PyIter_Next(self->input_iter); // Equivalent to calling `next(input_iter)` 
     if (lineobj == NULL) { 
      /* End of input OR exception */ 
      if (!PyErr_Occurred() && (self->field_len != 0 || 
             self->state == IN_QUOTED_FIELD)) { 
       if (self->dialect->strict) 
        PyErr_SetString(_csvstate_global->error_obj, 
            "unexpected end of data"); 
       else if (parse_save_field(self) >= 0) 
        break; 
      } 
      return NULL; 
     } 

正如你所看到的,next(reader_object)調用next(file_object)內部。所以你要一行一行地迭代,而不是將整個事情讀入內存。

0

我用這個函數。 其基本思想是讓生成器生成文件中的數字。

def iter_loadtxt(filename, delimiter=',', skiprows=0, read_range=None, dtype=float): 
    ''' 
    Read the file line by line and convert it to Numpy array. 
    :param delimiter: character 
    :param skiprows : int 
    :param read_range: [int, int] or None. set it to None and the function will read the whole file. 
    :param dtype: type 
    ''' 
    def iter_func(): 
     with open(filename, 'r') as infile: 
      for _ in range(skiprows): 
       next(infile) 
      if read_range is None: 
       for line in infile: 
        line = line.rstrip().split(delimiter) 
        for item in line: 
         yield dtype(item) 
      else: 
       counter = 0 
       for line in infile: 
        if counter < read_range[0]: 
         counter += 1 
        else: 
         counter += 1 
         for item in line: 
          yield dtype(item) 

        if counter >= read_range[1]: 
         break 

     iter_loadtxt.rowlength = len(line) 

    data = np.fromiter(iter_func(), dtype=dtype) 
    data = data.reshape((-1, iter_loadtxt.rowlength)) 
    return data