Ký tự cuối cùng trong tập tin là gì?


19

Tôi chỉ đọc câu trả lời cho "Xóa một ký tự dòng mới ở cuối tệp" và mọi người nói sẽ xóa ký tự cuối cùng. Câu hỏi của tôi là, không phải là nhân vật eof cuối cùng?



1
@SorenBjornstad Tôi cũng muốn thêm rằng khi có một dòng mới ở cuối tệp văn bản Unix, thì nó ở đó bởi vì nó chấm dứt dòng cuối cùng. Một tệp văn bản trống không có dòng mới ở cuối: đó là một chuỗi các ký tự bằng không.
Kaz

3
Để được mô tả một chút, CPM và DOS đã sử dụng ^ Z làm ký tự EOF và đôi khi bạn vẫn có thể gặp các tệp kết thúc bằng ^ Z.
Edward Falk

Câu trả lời:


13

Một tệp không kết thúc bằng ký tự Kết thúc tệp, vì các câu trả lời trước đó nêu chính xác. Nhưng tôi nghĩ rằng các câu trả lời và bình luận có chứa một số điểm không chính xác đáng để chỉ ra:

  • Bộ ký tự ASCII không chứa ký tự EOF chính xác. Có một số ký tự điều khiển "kết thúc": Kết thúc văn bản (3), Kết thúc truyền (4), Kết thúc khối truyền (23), Kết thúc trung bình (25). Dấu tách tệp (28) có thể đến gần nhất với ký tự EOF. Mã 26 là "Thay thế", không phải EOF.

  • Ctrl- Dchỉ được liên kết với đầu vào thiết bị đầu cuối. Ví dụ, lệnh cat filea fileb filec > outfilekhông liên quan Ctrl- D. Nhân tiện, bạn có thể thay đổi ký tự EOF của thiết bị đầu cuối thành một thứ khác ngoài Ctrl- Dsử dụng sttylệnh.

  • Nói đúng ra, Ctrl- D(hoặc bất cứ điều gì bạn đã thay đổi) không phải là mã khóa EOF. Những gì nó làm là làm cho readcuộc gọi hệ thống trở lại với những gì đầu vào có sẵn, giống như nhấn return làm cho cuộc gọi hệ thống đọc trả về một dòng ký tự cho người gọi. Theo quy ước, giá trị trả về bằng 0 từ lệnh gọi hệ thống đọc (tức là số 0 ký tự đọc) báo hiệu kết thúc điều kiện tệp. Tuy nhiên, tệp đầu vào không được đóng tự động và, nếu đầu vào đến từ thiết bị đầu cuối, nó không được đặt ở trạng thái "cuối tệp". Bạn có thể viết chương trình tiếp tục đọc từ thiết bị đầu cuối ngay cả sau khi "kết thúc tập tin" và cuộc gọi đọc có thể trả về giá trị khác không cho dòng đầu vào tiếp theo.

  • Sự tương tự giữa các ký tự eof và eol có thể được nhìn thấy nếu Ctrl- Dđược nhấn khi một số đầu vào đã được ghi trên dòng. Ví dụ: nếu bạn viết "abc" và nhấn Ctrl- Dcuộc gọi đọc trả về, lần này với giá trị trả về là 3 và với "abc" được lưu trong bộ đệm được truyền dưới dạng đối số. Vì đọc không trả về 0, nên điều này không được hiểu là điều kiện EOF theo quy ước ở trên. Tương tự, nhấn return để thực hiện trả lại cuộc gọi đã đọc với toàn bộ dòng đầu vào (bao gồm cả dòng mới). Bạn có thể thử điều này với catlệnh: viết một số ký tự trên dòng và nhấn Ctrl- D. Bạn sẽ thấy các nhân vật lặp lại với bạn và catchờ thêm đầu vào.

  • Tất cả những điều trên chỉ áp dụng khi thiết bị đầu cuối ở chế độ "nấu", trái ngược với chế độ "thô", trong đó xử lý đầu vào dòng được giảm thiểu. Trong chế độ thô, một ký tự Ctrl-D thực sự được gửi đến bộ đệm đầu vào.


19

Các ký tự điều khiển ASCII có các định nghĩa từ những năm 1960 (thực ra trước những gì bạn có thể xem là một mạng ). Không phải tất cả các ký tự điều khiển đó đều được sử dụng theo cách mà chúng được xác định cho thiết bị viễn thông hồi đó.

Trên các hệ thống giống Unix, không cần phải có EOFký tự; không cái nào được sử dụng Hệ thống có thể cho các ứng dụng biết có bao nhiêu byte trong một tệp:

  • Trên một số hệ thống khác (được thấy trong VMS, DOS, Windows), control-Z có thể hoạt động như một điểm đánh dấu cuối tệp vì trong các phiên bản , hệ thống không thể cho một số ứng dụng biết có bao nhiêu byte trong tệp.

    Trong trường hợp của VMS, hạn chế là do cách thức hoạt động của thời gian chạy C. Các ứng dụng ngôn ngữ hội có thể (và đã) có được kích thước tệp chính xác.

  • Các hệ thống Unix trong shell thường sử dụng control-D để báo cho ứng dụng biết đã kết thúc đầu vào (tệp), nhưng control-D không được lưu trong tệp.

Trong C, EOFđược thực hiện một cách có chủ đích -1để chỉ ra rằng nó không phải là một ký tự hợp lệ. I / O tiêu chuẩn trả về EOFkhi phát hiện tình trạng cuối tập tin - không phải là ký tự đặc biệt.

Nhân tiện, các tệp không cần kết thúc bằng ký tự dòng mới (ASCII line-feed). Trình chỉnh sửa văn bản có thể đối phó với các tệp là tất cả văn bản có thể in nhưng thiếu một dòng mới.


8
POSIX định nghĩa một tệp văn bản là một tệp chứa một chuỗi các dòng và lần lượt mỗi dòng là một chuỗi các ký tự không phải dòng mới theo sau là một dòng mới. Do đó, một tệp kết thúc bằng bất cứ thứ gì ngoại trừ 0x0A không phải là tệp văn bản phù hợp.
Damian Yerrick

2
Tôi biết điều đó, đó là lý do tại sao tôi chỉ ra rằng các trình soạn thảo văn bản hoạt động. (Tệp nhị phân không có ràng buộc như vậy).
Thomas Dickey

Điều thực sự đáng chú ý là các tệp dự định được xử lý dưới dạng văn bản không có dòng mới vẫn là dạng xấu (ngay cả khi các trình soạn thảo văn bản điển hình đã được mã hóa để bù cho các tệp đó), ít nhất là nếu bạn thực sự muốn nó rộng rãi sử dụng / tương thích, vì thiếu một ký tự dòng mới có thể thêm khó khăn thêm trong những hoàn cảnh khác nhau (concatenating / in nhiều file văn bản, phân tích với các công cụ điển hình dòng lệnh, biên tập viên tối thiểu như busybox's vi, vv).
mtraceur

(1) Trước VMS, RT-11 RSX-11 TOPS-10 có hệ thống tập tin chỉ chính xác với một khối và cần một ký tự EOF. CP / M cũng vậy, dường như đã sao chép nó từ DEC và lần lượt được sao chép bởi MS-DOS đầu tiên và sau đó được truyền lại cho Windows. (2) Trong Unix, trình điều khiển tty không phải là shell, như được mô tả chi tiết hơn bởi JohanM, mặc dù mọi người thường chạy shell trên các thiết bị tty.
dave_thndry_085

Chắc chắn - DEC đã trở lại đó (và lưu ý rằng tôi đã đề cập đến các phiên bản cũ hơn ). Cho dù đó là nguồn gốc của tính năng CP / M sẽ là một chủ đề thú vị để khám phá (không phải ở đây); Tôi đã đề cập đến những trường hợp để đưa ra một số nền tảng cho các lựa chọn thay thế.
Thomas Dickey

7

EOF không phải là một nhân vật. Đây là trạng thái cho biết không còn ký tự nào để đọc từ luồng tệp. Khi bạn nhập lệnh EOF từ thiết bị đầu cuối, bạn đang báo hiệu cho HĐH để đóng luồng đầu vào, không đưa vào một ký tự đặc biệt.


1
Có nhưng trong bảng ASCII EOF là 26 vì vậy tôi nghĩ rằng byte cuối cùng là biểu diễn nhị phân của 26. Vậy làm thế nào để một chương trình đọc đầu vào biết nó kết thúc ở đâu?
sworwitz

ASCII có nghĩa là để truyền thông tin qua mạng. Trong trường hợp đó, bạn cần một ký tự EOF. (ASCII cũng có rất nhiều mã kiểm soát. Không phải mọi thứ đều có thể in được.) Trong trường hợp luồng tệp, kích thước của tệp đã được biết qua hệ thống tệp để HĐH có thể biết khi nào không có thêm dữ liệu để đọc.
Munir

@sworwitz: Liên quan đến C, các hàm đọc đầu vào trả về một ký tự cho mỗi cuộc gọi trả về một int (thường là số 32 bit nhưng phải tối thiểu 16 bit) không phải là char. Hàm tín hiệu và EOF bằng cách trả về -1 (0xffffffff) không phải là giá trị 8 bit hợp lệ nên sẽ không bị nhầm lẫn bởi bất kỳ ký tự ASCII nào, thậm chí là 0xff. Các hàm trả về một chuỗi cũng trả về độ dài của dữ liệu đọc. Độ dài này có thể được sử dụng để báo hiệu không có dữ liệu hoặc kết thúc dữ liệu (một lần nữa, độ dài có thể là -1). Cuối cùng, cũng có một chức năng mà bạn có thể gọi sẽ cho bạn biết nếu một luồng đã kết thúc
slebetman

Ok cảm ơn bạn! Vì vậy, khi bash tôi nhấn Ctrl + d tôi nhập đầu vào ký tự ASCII, phải không?
sworwitz

@sworwitz Không chính xác. Trước khi bashchạm tay vào đầu vào, nó được trình điều khiển TTY mát xa. Trình điều khiển này chặn Ctrl-D và gửi EOF tới bash (Trong đó EOF không phải là ký tự, nhưng là trạng thái tệp đặc biệt)
Stig Hemmer
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.