2012-01-20 39 views
5

Giả sử có một tệp test.txt có chứa một chuỗi 'test'.Rác trong hồ sơ sau khi truncate (0) bằng Python

Bây giờ, hãy xem xét mã Python sau:

f = open('test', 'r+') 
f.read() 
f.truncate(0) 
f.write('passed') 
f.flush(); 

Bây giờ tôi mong đợi test.txt chứa 'passed' bây giờ, tuy nhiên có thêm một số biểu tượng kỳ lạ!

Cập nhật: tuôn ra sau khi cắt ngắn không giúp được gì.

+1

Theo như tôi có thể nói, chạy 'truncate (0)' chỉ cần đặt kích thước tệp thành 0 byte và di chuyển con trỏ tệp trở lại đầu bộ đệm. Khi bạn ghi vào luồng trước khi xóa, trạng thái của bộ đệm không được xác định. Khi bạn tuôn ra, dữ liệu rác có thể xuất hiện từ bộ đệm đó. Quy tắc chung tôi sẽ áp dụng là bạn nên tuôn ra bất cứ khi nào bạn cố gắng * loại bỏ * bất kỳ thứ gì hoặc khi bạn cần đảm bảo tệp ở trạng thái cụ thể trước khi tiếp tục. – Polynomial

+0

điều gì về việc đóng tệp? – joaquin

+0

@ Đa thức tuôn ra cũng không hoạt động, tôi bị nhầm lẫn ... – Beginner

Trả lời

4

Điều này là do truncate không thay đổi vị trí luồng.

Khi bạn read() tệp, bạn di chuyển vị trí đến cuối. Vì vậy, kế tiếp write s sẽ ghi vào tệp từ vị trí đó. Tuy nhiên, khi bạn gọi flush(), có vẻ như không chỉ nó cố gắng ghi bộ đệm vào tệp, mà còn có một số lỗi kiểm tra và sửa vị trí tệp hiện tại. Khi Flush() được gọi sau truncate(0), không viết gì (bộ đệm trống), sau đó kiểm tra kích thước tệp và đặt vị trí tại vị trí áp dụng đầu tiên (là 0).

CẬP NHẬT

chức năng tập tin Python của không chỉ hàm bao quanh tương đương tiêu chuẩn thư viện C, nhưng biết các chức năng C giúp hiểu biết những gì đang xảy ra chính xác hơn.

Từ ftruncate man page:

Giá trị của con trỏ tìm kiếm không được sửa đổi bởi một cuộc gọi đến ftruncate().

Từ fflush man page:

Nếu điểm dòng để thêm một input stream hoặc một dòng cập nhật vào đó các hoạt động gần đây nhất là đầu vào, dòng đó là đỏ ửng nếu nó là seekable và chưa được ở cuối -tập tin. Flushing một luồng đầu vào sẽ loại bỏ bất kỳ đầu vào đệm nào và điều chỉnh con trỏ tệp sao cho thao tác nhập tiếp theo truy cập byte sau lần đọc cuối cùng.

Điều này có nghĩa là nếu bạn đặt flush trước truncate thì không có hiệu lực. Tôi đã kiểm tra và nó là như vậy.

Nhưng đối với việc đưa flush sau truncate:

Nếu điểm dòng để một output stream hoặc một dòng cập nhật trong đó các hoạt động gần đây nhất là không đầu vào, fflush() gây ra bất kỳ dữ liệu bất thành văn cho dòng đó là được ghi vào tệp và các trường st_ctime và st_mtime của tệp cơ bản được đánh dấu để cập nhật.

Trang người đàn ông không đề cập đến con trỏ tìm kiếm khi giải thích luồng đầu ra với thao tác cuối cùng không được nhập. (Ở đây hoạt động cuối cùng của chúng tôi là truncate)

UPDATE 2

tôi tìm thấy một cái gì đó trong mã nguồn python: Python-3.2.2\Modules\_io\fileio.c:837

#ifdef HAVE_FTRUNCATE 
static PyObject * 
fileio_truncate(fileio *self, PyObject *args) 
{ 
    PyObject *posobj = NULL; /* the new size wanted by the user */ 
#ifndef MS_WINDOWS 
    Py_off_t pos; 
#endif 

... 

#ifdef MS_WINDOWS 
    /* MS _chsize doesn't work if newsize doesn't fit in 32 bits, 
     so don't even try using it. */ 
    { 
     PyObject *oldposobj, *tempposobj; 
     HANDLE hFile; 

////// THIS LINE ////////////////////////////////////////////////////////////// 
     /* we save the file pointer position */ 
     oldposobj = portable_lseek(fd, NULL, 1); 
     if (oldposobj == NULL) { 
      Py_DECREF(posobj); 
      return NULL; 
     } 

     /* we then move to the truncation position */ 
     ... 

     /* Truncate. Note that this may grow the file! */ 
     ... 

////// AND THIS LINE ////////////////////////////////////////////////////////// 
     /* we restore the file pointer position in any case */ 
     tempposobj = portable_lseek(fd, oldposobj, 0); 
     Py_DECREF(oldposobj); 
     if (tempposobj == NULL) { 
      Py_DECREF(posobj); 
      return NULL; 
     } 
     Py_DECREF(tempposobj); 
    } 
#else 

... 

#endif /* HAVE_FTRUNCATE */ 

Nhìn vào hai dòng Tôi chỉ (///// This Line /////). Nếu nền tảng của bạn là Windows, thì nó sẽ lưu vị trí và trả lại nó sau khi cắt bớt.

Thật ngạc nhiên, hầu hết các chức năng flush bên trong các chức năng Python 3.2.2 hoặc không làm gì hoặc không gọi hàm fflush C. Phần cắt ngắn 3.2.2 cũng rất không có giấy tờ. Tuy nhiên, tôi đã tìm thấy một cái gì đó thú vị trong Python 2.7.2 nguồn. Trước tiên, tôi thấy điều này trong Python-2.7.2\Objects\fileobject.c:812 trong truncate thực hiện:

/* Get current file position. If the file happens to be open for 
* update and the last operation was an input operation, C doesn't 
* define what the later fflush() will do, but we promise truncate() 
* won't change the current position (and fflush() *does* change it 
* then at least on Windows). The easiest thing is to capture 
* current pos now and seek back to it at the end. 
*/ 

Vì vậy, để tóm tắt tất cả, tôi nghĩ rằng đây là một nền tảng hoàn toàn phụ thuộc vào điều. Tôi đã kiểm tra mặc định Python 3.2.2 cho Windows x64 và nhận được kết quả tương tự như bạn. Không biết điều gì xảy ra trên * nixes.

+0

Xem cập nhật của tôi, nhưng tôi nghĩ bạn đang đi đúng hướng. Tôi có lẽ nên tìm kiếm thêm không. - Có tìm cách 0 ngay sau khi cắt bớt giúp! Vì vậy, mục đích thực sự của cắt ngắn sau đó là gì ?! – Beginner

+0

Hệ điều hành của tôi là Linux, vì vậy tôi nghi ngờ hành vi tương tự trên các hệ thống tương thích POSIX khác. – Beginner

-1

Điều đó tùy thuộc. Nếu bạn muốn giữ cho các tập tin mở và truy cập nó mà không cần đóng nó sau đó tuôn ra sẽ buộc ghi vào tập tin. Nếu bạn đóng tập tin ngay sau khi tuôn ra thì không bạn không cần nó vì gần sẽ tuôn ra cho bạn. Đó là sự hiểu biết của tôi từ số docs

+1

Tôi muốn xóa tệp ... và không, tôi không muốn mở lại. – Beginner

1

Cắt bớt không thay đổi vị trí tệp. Lưu ý rằng ngay cả khi tệp được mở bằng đọc + ghi, bạn không thể chỉ chuyển đổi giữa hai loại hoạt động (ví dụ: thao tác tìm kiếm được yêu cầu để có thể chuyển từ đọc sang viết hoặc ngược lại).

0

Tôi hy vọng sau đây là mã bạn có nghĩa là để viết:

open('test.txt').read() 
open('test.txt', 'w').write('passed') 
0

Yeah, đó là sự thật mà truncate() không di chuyển vị trí, nhưng nói rằng, là đơn giản như cái chết:

f.read() 
f.seek(0) 
f.truncate(0) 
f.close() 

điều này là hoàn toàn làm việc;)

Các vấn đề liên quan