Cân nhắc khi thiết kế một loại tệp


8

Tôi sắp bắt đầu viết một quy trình lưu một số cấu trúc dữ liệu từ mã vào một tệp thuộc loại độc quyền, chưa được xác định. Tuy nhiên, tôi chưa bao giờ thiết kế một loại tệp hoặc cấu trúc trước đây.

  • Có bất cứ điều gì, nói chung, mà tôi nên xem xét trước khi bắt đầu thiết kế của tôi?
  • Có bất kỳ thực hành tốt được chấp nhận ở đây? Thực hành xấu tôi nên tránh?
  • Bất kỳ tuyệt đối làm và không nên?

3
Xin chào từ năm 2016! Đây là định nghĩa trong sách giáo khoa về một câu hỏi quá rộng :) Sẽ hữu ích nếu bạn cung cấp chi tiết cụ thể về những gì bạn đang cố gắng đạt được. Hầu hết các định dạng tập tin độc quyền được thiết kế cho một cái gì đó . Yêu cầu của bạn là gì?
Andres F.

Đừng quên lợi ích chính của việc sử dụng định dạng chuẩn: các công cụ và ứng dụng khác sẽ có thể sử dụng nó dễ dàng hơn. Và bạn có thể không phải là người duy nhất làm việc với dữ liệu đó. Nếu bạn làm việc với nguyên tắc đó trong đầu, phần mềm của bạn sẽ linh hoạt hơn và điều đó có cách đơn giản hóa mọi thứ.
Joey Adams

Câu trả lời:


20

Trước tiên, hãy cố gắng tìm một định dạng đủ gần với những gì bạn sắp xây dựng. Nói chung, tốt hơn là sử dụng định dạng của ai đó hơn là phát minh ra định dạng của riêng bạn, ngay cả khi định dạng có vẻ phức tạp hơn một chút so với định dạng bạn cần 1 .

Nếu bạn không thể tìm thấy một định dạng sẵn sàng phù hợp, hãy xem liệu bạn có thể tự xây dựng trên định dạng mục đích chung hiện có, chẳng hạn như XML hoặc XML nhị phân . Điều này có thể có trong hầu hết các trường hợp khi bạn chuẩn bị bắt đầu một định dạng tệp mới. XML dựa trên văn bản chiếm nhiều không gian hơn, nhưng cung cấp cho con người một số biện pháp dễ đọc. Tuy nhiên, nếu bạn thấy mình sử dụng mã hóa Base-64 bên trong tệp XML, đó là một dấu hiệu rõ ràng rằng bạn nên sử dụng mã hóa nhị phân thay thế.

Theo như các thực tiễn tốt và xấu, hãy đảm bảo rằng bạn không "nướng" tính năng phần cứng của nền tảng đích ban đầu vào thiết kế định dạng tệp của bạn. Cụ thể, hãy chắc chắn rằng con số của bạn được lưu trữ trong một định dạng mà có thể được đọc một cách chính xác trên nền tảng với endianness đó là khác biệt so với các nhà văn, và rằng chuỗi diện người dùng của bạn được lưu trữ trong UNICODE.

Một thực hành tốt khác là bao gồm một tiêu đề mà từ đó có thể xác định loại tệp của bạn trong trường hợp phần mở rộng của nó bị thiếu hoặc không chính xác. Đó là một ý tưởng tốt để bao gồm một phiên bản định dạng tệp của bạn trong tiêu đề. Điều này sẽ cho phép bạn thay đổi định dạng sau và tương thích ngược.

Nếu có thể, đừng làm cho định dạng của bạn phụ thuộc vào các chi tiết cụ thể của cơ chế tuần tự hóa mặc định được tích hợp trong nền tảng của bạn. Ví dụ, các đối tượng Java được tuần tự hóa nhị phân không tạo ra định dạng tệp tốt 2 .

Cuối cùng, quyết định nếu các tập tin của bạn cần phải được streamable . Điều này giới thiệu sự phức tạp bổ sung, bởi vì người ta có thể giải thích các "khung" riêng lẻ của tệp của bạn. Tuy nhiên, trong trường hợp khi bạn cần khả năng truyền phát, bạn hầu như luôn có thể định vị một định dạng tệp phù hợp đã tồn tại.


1 Mặt khác, bạn nên tránh các định dạng đòi hỏi phải có những nỗ lực phi thường để hỗ trợ sự phức tạp mà ứng dụng của bạn yêu cầu.

2 Điều này không có nghĩa là, tuy nhiên, bạn không nên cố gắng để tùy chỉnh tích hợp đọc và viết các định dạng mới của bạn với chương trình tuần tự của nền tảng của bạn, chỉ là bạn không nên dựa vào các cơ chế mặc định của serialization.


3
Unicode không phải là một định dạng. Nó chỉ là một bản đồ. UTF-8 là một định dạng và thường được coi là định dạng phù hợp cho các chuỗi văn bản di động (trừ khi bạn xử lý văn bản CJK trong trường hợp tôi nghĩ UTF-16LE có thể là định dạng phổ biến tiếp theo cho các chuỗi)
squarewav

12

Điều đầu tiên bạn nên xem xét là liệu bạn có thực sự cần một định dạng mới hay bạn có thể nhận được bằng cách sử dụng một định dạng đã tồn tại. Cân nhắc sử dụng SQLite; nếu bạn có thể điều chỉnh các nhu cầu của mình để phù hợp với mô hình RDBMS, điều này có thể giúp bạn tiết kiệm rất nhiều vấn đề đau đầu. Ngoài ra, hãy xem xét sử dụng XML hoặc JSON, điều này sẽ giúp bạn không phải viết trình phân tích cú pháp của riêng bạn.

Nếu bạn phải tạo định dạng của riêng mình, việc xem xét đầu tiên là bạn muốn định dạng văn bản hay định dạng nhị phân. Có lợi thế cho cả hai. Một định dạng văn bản là một chiến thắng lớn cho tính di động và có lợi thế là dễ dàng hơn cho con người để đọc hoặc chỉnh sửa. Một định dạng nhị phân có thể hiệu quả hơn, nhưng nó có rất nhiều vấn đề về tính di động đi kèm với nó. Đừng cố đọc byte trực tiếp vào các biến, bạn sẽ hối tiếc nếu bạn cần chuyển mã sang nền tảng khác.


Ngoài ra, hãy nhớ rằng khi thiết kế định dạng của riêng bạn, bạn PHẢI tài khoản cho các tệp bị hỏng và đảm bảo chúng sẽ không phá vỡ ứng dụng của bạn. Ngoài ra, nếu sử dụng XML, xin vui lòng, vì tình yêu của tất cả những gì quý giá đối với bạn: SỬ DỤNG AN PARSER. Không quan trọng cái nào (ngôn ngữ của bạn có thể cung cấp một cái), nhưng KHÔNG PARSE XML CỦA BẠN.
Michael Kohne

SQLite nếu bạn cần một cơ sở dữ liệu với các bản ghi riêng lẻ có thể được thay đổi ngay lập tức. JSON nếu đọc tất cả dữ liệu vào bộ nhớ, sửa đổi nó trong bộ nhớ, sau đó ghi lại vào tệp.
gnasher729 ngày

1
@MichaelKohne: Tương tự cho JSON. Tôi ước tính 10% câu hỏi của iOS là về sự cố khi một số JSON chứa null nơi họ mong đợi một chuỗi.
gnasher729

2

Quyết định đầu tiên và quan trọng nhất của bạn là sử dụng định dạng nhị phân hay dựa trên văn bản. Nhị phân là cách để đi khi bạn phải đổ một lượng lớn vào dữ liệu không phải là chuỗi. Nhưng nó có nhược điểm đáng kể:

  • Dữ liệu nhị phân không thể đọc được. Do đó, nó làm cho việc gỡ lỗi và / hoặc điều chỉnh dữ liệu đã có trên đĩa khó hơn nhiều. Đây là một trong những lý do tại sao triết lý UNIX mạnh mẽ chấp nhận các tệp dựa trên văn bản.

  • Các định dạng nhị phân không cho vay để mở rộng trong tương lai. Trong khi điều này có thể được thực hiện, các điểm cho khả năng mở rộng cần phải được xây dựng thành định dạng ngay từ đầu. Thông thường, đây là

    1. một số / chuỗi ma thuật xác định định dạng

    2. số phiên bản định dạng

    3. các trường dành riêng tại các vị trí chiến lược, phải được khởi tạo bằng không

    Hai trường đầu tiên thường xuất hiện ngay ở phần đầu của tệp, trong khi các trường dành riêng thường nằm rải rác trên tệp.


Bây giờ, nếu bạn đi theo lộ trình dựa trên văn bản, đây là một số điều cần suy nghĩ:

  • Bất kỳ định dạng dựa trên văn bản xác định một ngôn ngữ nhỏ mới. Biết điều này và sử dụng nó để lợi thế của bạn.

  • Cố gắng giữ cho các quy tắc của ngôn ngữ nhỏ của bạn đơn giản nhất có thể. Không có nơi nào mà nguyên tắc KISS quan trọng hơn khi thiết kế định dạng tệp dựa trên văn bản.

  • Cố gắng làm cho các tập tin của bạn tự giải thích.

  • Đừng áp đặt các hạn chế không cần thiết, như nơi khoảng trắng có thể xuất hiện và bao nhiêu khoảng trắng.

  • Hãy xem xét một số định dạng tệp khác nhau được phát triển cho UNIX. Điều này có thể cung cấp cho bạn khá nhiều ý tưởng tốt.

  • Nếu có thể sử dụng hoặc điều chỉnh / mở rộng / hạn chế một định dạng tệp hiện có. Các định dạng json là một điểm khởi đầu khá dễ đọc, tốt. (Ít nhất là tốt hơn nhiều so với XML, đó là một nỗi đau để đọc cho con người.)

  • Nếu kích thước tệp là một vấn đề, bạn có thể xem xét sử dụng định dạng dựa trên văn bản, nhưng chuyển nó qua một trong các máy nén tiêu chuẩn như gziphoặc lzma. Các máy nén tiêu chuẩn thích đầu vào như thế.


Nếu bạn đi theo con đường nhị phân, đây là một số điều cần chú ý:

  • Bạn nên có một tiêu đề với số / chuỗi ma thuật và số phiên bản. Thông thường, điều này đi đến phần đầu của tệp, nhưng nó cũng có thể đi đến phần cuối của tệp. Một số tệp thậm chí có thể có hai tiêu đề khác nhau ở phía trước và phía sau, đưa ra hai chế độ xem độc lập về dữ liệu bên trong.

  • Bạn nên có một chỉ mục, và bạn nên cố gắng giữ các phần của nó gần nhau. Điều này cho phép người đọc nhanh chóng tìm ra những gì bên trong tệp mà không cần phải quét toàn bộ. Nếu bạn không làm điều đó, bạn có thể sẽ đọc mọi thứ hai lần.

  • Nếu bạn có các bit của tệp chỉ có thể truy cập dưới dạng chuỗi thay vì thông qua cấu trúc chỉ mục, hãy bao gồm ít nhất một trường độ dài cho mỗi bản ghi trong chuỗi. Một chỉ mục hoặc các trường có độ dài như vậy là yêu cầu đối với những người đọc không hiểu tất cả các chi tiết về định dạng của bạn và cần bỏ qua các phần của nó dưới dạng hộp đen. (Cám ơn Jules vì ​​điều này.)

  • Mỗi đối tượng dữ liệu trong tệp cần chứa ít nhất một trường dành riêng để mở rộng trong tương lai. Điều này không cần phải lớn, nhưng nó cần phải ở đó. Bởi vì, nếu không, không có nơi nào bạn có thể nhận ra các tính năng trong tương lai.

  • Bạn cần phải tính đến endianess. Thông thường, điều đó có nghĩa là bạn quyết định một lần liệu các tệp của bạn sẽ được mã hóa theo thứ tự byte cuối lớn hay cuối nhỏ và tuân theo quyết định đó: Xử lý endianess như thế này là một điều phiền toái, nhưng không đến nỗi phải tính đến hai phiên bản khác nhau của endianess trong tập tin.

  • Hãy hào phóng trong chiều rộng của các lĩnh vực mà bạn cung cấp. Đặc biệt, khi bạn cần mã hóa offset trong tệp, luôn sử dụng 64 bit. Nhiều người đau đầu đã gây ra bởi các nhà thiết kế định dạng tệp quá bảo thủ với số lượng bit họ phân bổ.


Tôi sẽ thêm một cái khác cho các tệp nhị phân: nếu bạn có một chuỗi các bản ghi thuộc loại khác nhau (đó là một cấu trúc rất hữu ích) KHÔNG cho rằng bất kỳ người đọc nào của tệp đều hiểu tất cả các loại. Sử dụng các chỉ số chiều dài để hồ sơ không xác định có thể được bỏ qua.
Jules

@Jules Đúng bạn là :-) Tôi đã thêm vào đó là điểm 3 cho các tệp nhị phân.
cmaster - phục hồi monica

0

Nó thực sự phụ thuộc vào những gì bạn đang làm. Nó nên đơn giản nhất có thể và không đơn giản. Tôi thấy rất nhiều người khác đẩy XML. Tôi đặc biệt không khuyến khích việc sử dụng XML. XML là một mớ hỗn độn được chỉ định quá mức. Câu hỏi đầu tiên là cấu trúc dữ liệu của bạn có các nhánh. Có nghĩa là họ liệt kê danh sách hoặc danh sách bản đồ hay như vậy? Nếu không, thì một chuỗi các bản ghi văn bản đơn giản có thể là tốt. CSV có thể.

Nếu bạn cần hiệu suất hoặc truy cập ngẫu nhiên, nhị phân là tốt. Xác định một chuỗi các bản ghi trong đó mỗi bản ghi chứa một chuỗi các mốc có kích thước cụ thể như một số nguyên cuối nhỏ 4 byte cho một số hoặc một số nguyên 2 byte chỉ định số byte cho chuỗi UTF-8. Tạo mỗi bản ghi bắt đầu bằng một số nguyên chỉ định kích thước của bản ghi để có thể quét toàn bộ tệp mà không thực sự đọc nội dung của các bản ghi. Điều này cũng cho phép bạn mã hóa các bản ghi tại chỗ (nghĩa là bạn có thể mmap tệp, mã hóa bản ghi và sau đó cập nhật kích thước sau để giảm thiểu việc sao chép không cần thiết). Đây là loại điều mà bạn không thể làm với XML.

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.