2013-02-14 29 views
5

Tôi đang đùa giỡn với một số mã đang mở, đọc và sửa đổi tệp văn bản. Một cách nhanh chóng (giản thể) ví dụ sẽ là:Sử dụng "r +" trong fopen trên windows vs linux

#include <stdio.h> 
int main() 
{ 
    FILE * fp = fopen("test.txt", "r+"); 
    char line[100] = {'\0'}; 
    int count = 0; 
    int ret_code = 0; 
    while(!feof(fp)){ 
     fgets(line, 100, fp); 
     // do some processing on line... 
     count++; 
     if(count == 4) { 
      ret_code = fprintf(fp, "replaced this line\n"); 
      printf("ret code was %d\n", ret_code); 
      perror("Error was: "); 
     } 
    } 
    fclose(fp); 
    return 0; 
} 

Bây giờ trên Linux, biên dịch với gcc (4.6.2) mã này chạy, và sửa đổi dòng thứ 5 của tập tin. Cùng một mã, chạy trên Windows7 được biên dịch với Visual C++ 2010 chạy và tuyên bố đã thành công (báo cáo một mã trả về 19 ký tự và perror nói "Không có lỗi") nhưng không thay thế được dòng.

Trên Linux tập tin của tôi có quyền truy cập đầy đủ:

-rw-rw-rw- 1 mike users 191 Feb 14 10:11 test.txt 

Và như xa như tôi có thể nói nó giống trên Windows:

test.txt (click chuột phải) -> properties -> Bảo mật
"Cho phép" được chọn để đọc & Viết cho người dùng, Hệ thống và Quản trị viên.

Tôi nhận được kết quả tương tự bằng cách sử dụng gcc của MinGW trên Windows để tôi biết đó không phải là tính năng Visual C++ ".

Tôi có thiếu điều gì đó hiển nhiên hay không thực tế là tôi không gặp lỗi, nhưng cũng không có kết quả "tính năng" không sử dụng của r+ với fopen() trên Windows?


EDIT:
vẻ ngay cả ở Microsoft's site họ nói "r +" nên mở để đọc văn bản. Họ cũng đã lưu ý:

Khi loại truy cập "r +", "w +" hoặc "a +" được chỉ định, cho phép đọc và ghi (tệp được cho là mở để "cập nhật") . Tuy nhiên, khi bạn chuyển đổi giữa đọc và viết, phải có một thao tác fflush xen kẽ, fsetpos, fseek hoặc tua lại. Vị trí hiện tại có thể được chỉ định cho hoạt động fsetpos hoặc fseek, nếu muốn.

Vì vậy, tôi đã cố gắng:

 ... 
     if(count == 4) { 
      fflush(fp); 
      ret_code = fprintf(fp, "replaced this line\n"); 
      fflush(fp); 
      printf("ret code was %d\n", ret_code); 
      ... 

vô ích.

+0

Bạn đã thử xả luồng bằng cách sử dụng 'fflush' sau thao tác ghi? – Cyclonecode

+3

Tôi không chắc đó có phải là vấn đề hay không, nhưng bạn có thể cần phải gọi 'fseek' khi chuyển đổi giữa đọc và viết từ tập tin – Hasturkun

+0

@KristerAndersson - yup, chỉ cần cập nhật để làm rõ tôi thấy ghi chú tại trang MSDN nói rằng bạn nên cập nhật các dòng bởi một trong những 'f ()' vì vậy tôi đã cố gắng 'fflush()' ing trước và sau khi viết, nhưng không có con xúc xắc. – Mike

Trả lời

3

Theo Linux man page for fopen():

Đọc và viết có thể được trộn lẫn vào dòng đọc/ghi theo thứ tự nào. Lưu ý rằng ANSI C yêu cầu chức năng định vị tập tin can thiệp giữa đầu ra và đầu vào, trừ khi hoạt động đầu vào gặp kết thúc tệp. (Nếu điều kiện này không được đáp ứng, thì đọc được cho phép trả về kết quả của các bài viết không phải là mới nhất.) Vì vậy, nó là thực hành tốt (và thực sự đôi khi cần thiết trong Linux) để đặt một fseek (3) hoặc Hoạt động fgetpos (3) giữa hoạt động ghi và đọc trên luồng như vậy. Thao tác này có thể là một rõ ràng không-op (như trong fseek (..., 0l, SEEK_CUR) kêu gọi đồng bộ hóa tác dụng phụ của nó.

Vì vậy, bạn nên luôn luôn gọi fseek() (như, ví dụ.fseek(..., 0, SEEK_CUR)) khi chuyển đổi giữa đọc và ghi từ một tệp.

+1

Đó là vấn đề, và đó là những gì tôi nhận được để đọc tài liệu MSDN thay vì trang người đàn ông. :) cảm ơn. – Mike

+0

Lưu ý rằng các tài liệu gần đây nhất từ ​​MSDN (cho VS 2012) đã được cập nhật: http://msdn.microsoft.com/en-us/library/yeby3zcb.aspx –

+0

@MichaelBurr - Điểm tốt, đó không phải là tài liệu gần đây, tôi nên cập nhật bookmark của tôi, được một thời gian kể từ khi tôi đã ở đó. – Mike

3

Trước khi thực hiện đầu ra sau khi nhập, fflush() không tốt - bạn cần thực hiện thao tác tìm kiếm. Một cái gì đó như:

fseek(fp, ftell(fp), SEEK_SET); // not fflush(fp); 

từ tiêu chuẩn C99 (7.19.5.3/6 "The functoin fopen):

Khi một tập tin được mở ra với chế độ cập nhật ('+' là thứ hai hoặc thứ ba Trong đầu danh sách các giá trị đối số của chế độ), cả đầu vào và đầu ra đều có thể được thực hiện trên luồng liên kết, tuy nhiên, đầu ra sẽ không được theo dõi trực tiếp bằng đầu vào mà không có lệnh gọi đến chức năng fflush hoặc chức năng định vị tệp (fseek, fsetpos hoặc tua lại) và đầu vào sẽ không được theo dõi trực tiếp bởi đầu ra mà không có cuộc gọi can thiệp vào chức năng định vị tệp, trừ khi thao tác nhập gặp phải kết thúc tệp.

+0

Thật buồn cười, bạn nói "fflush() không tốt" nhưng sau đó đoạn trích C99 mà bạn trích dẫn cho biết: "không có cuộc gọi can thiệp vào hàm fflush HOẶC đến hàm định vị tệp'. Vì vậy, ngay tại đó nó nói 'fflush()' OR 'fseek()'/các hàm định vị khác. – Mike

+2

Đó là cho đầu ra theo sau là đầu vào. Vấn đề của bạn là trong thực hiện đầu vào theo sau đầu ra, mà cần một cuộc gọi định vị tập tin can thiệp (hoặc EOF). Tôi sẽ nói rằng đây là loại khó khăn để đọc để có được tất cả các điều kiện thẳng trong đầu của bạn - một bảng sẽ làm việc tốt hơn. –

+0

+1 đã nhận được điều đó, điều đó tạo nên sự quan tâm vì sao các vấn đề đặt hàng. Cảm ơn bạn đã nhập. – Mike

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