Tại sao chúng ta không thể chèn vào các tập tin mà không ghi thêm? (Tôi không có nghĩa là chắp thêm, cũng không viết quá nhiều)


8

Điều này xảy ra như là một vấn đề độc lập ngôn ngữ lập trình với tôi.

Tôi có một tập tin với nội dung

aaabddd

Khi tôi muốn chèn Cphía sau bthì mã của tôi cần phải viết lại dddđể có được

aaabCddd

Tại sao tôi không thể chỉ chèn Cvào vị trí này?

Tôi không thể làm điều này trong Java, Python, .... Tôi không thể làm điều này trong Linux, Windows, .... Tôi có đúng không

Tôi không hiểu tại sao Ckhông thể đơn giản được chèn mà không cần viết thêm. Ai đó sẽ giải thích tại sao điều này là như vậy?


2
Hãy suy nghĩ về những gì xảy ra với các bit trên đĩa khi bạn muốn 'chèn' thứ gì đó vào byte 128 của tệp 2 gigabyte.

Bạn có nghĩa là không có hệ điều hành và không có hệ thống tập tin ở giữa? Sau đó, nó sẽ không hoạt động. Với hai cái kia, tôi không biết tại sao nó không thể hoạt động.
Người dùng

12
Lấy 500 domino và đặt chúng từ đầu đến cuối trong một dòng. Bây giờ hãy thử chèn một dòng vào dòng đó mà không di chuyển các dòng khác.
GrandmasterB

2
@MichaelT Trong thế giới giấc mơ của tôi, bạn nên chỉ cần chèn một khối vào chuỗi các khối tạo nên tập tin và phân phối các nội dung của khối đầu tiên hiện lên hai khối đầu tiên. Cấp, điều này sẽ đòi hỏi người thực hiện hệ thống tập tin để xử lý khối lẻ cỡ - nhưng trong tình huống mà bạn làm cần hoạt động này, nó sẽ nâng cao hiệu quả quá nhiều nó thậm chí không buồn cười.
Kilian Foth

1
@User các câu hỏi về phân mảnh hệ thống tập tin và cách thức hoạt động của Ext4 di chuyển vững chắc vào vương quốc của SuperUser. Hãy nhớ chỉ định đầy đủ vấn đề của bạn hoặc họ sẽ hỏi lại về byte. Bạn đang hỏi về các khối và hệ thống tệp và trình quản lý khối hợp lý và tương tự.

Câu trả lời:


8

Do hầu hết các hệ thống tệp lưu trữ nội dung của các tệp trong các khối riêng lẻ không nhất thiết phải liền kề trên đĩa vật lý, nhưng được liên kết qua các cấu trúc con trỏ, có vẻ như chế độ đó - "chèn" thay vì "nối thêm" hoặc "ghi đè" - nên để có thể, và chắc chắn có thể được thực hiện hiệu quả hơn những gì chúng ta phải làm bây giờ: đọc toàn bộ nội dung, chỉnh sửa luồng byte và viết lại toàn bộ nội dung.

Tuy nhiên, dù tốt hay xấu, ngữ nghĩa UNIX của các hệ thống tệp được thiết kế theo mô hình "thô và đơn giản" vào những năm 1970: nó cho phép bạn làm mọi thứ, nhưng không nhất thiết phải theo cách hiệu quả nhất có thể. Ngày nay, gần như không thể tưởng tượng được việc giới thiệu chế độ mở tệp mới vào lớp Hệ thống tệp ảo và có bất kỳ hy vọng nào về các hệ thống tệp chính áp dụng hỗ trợ cho nó. Đây là một tiểu thú cưng của tôi, nhưng tiếc là người ta không thể giải quyết sớm được.


2
Tòa nhà có thể tạo ra một dự án phụ thú vị trong một thời gian ...
Thất

1
Lưu trữ cấp khối làm phức tạp thêm câu hỏi một bước nữa. Bám sát ví dụ ban đầu của OP, hai phiên bản của chuỗi phải khớp trong một khối. Các byte cần phải được viết ra một cách tuần tự và đó là những gì bắt buộc phải dịch chuyển phần đuôi của chuỗi xuống bằng bất cứ số lượng nào được chèn vào.

Sẽ chỉ hiệu quả nếu bạn phải chèn chính xác lượng dữ liệu có thể được lưu trữ trong một khối, chính xác là đường viền giữa hai khối hiện có.
Idan Arye

Đường may Kilian Forth là đúng. Tôi đã hỏi một giáo sư về điều này và anh ấy nói với tôi về điều tương tự: Thiết kế "thô và đơn giản" cho phép tính di động và do đó được sử dụng rộng rãi hơn. Không có nhiều hệ thống tập tin cho phép chèn và thậm chí ít hệ điều hành tiếp xúc với nó, để áp dụng cho giao diện di động. @ GlenH7 Hai người đã chỉnh sửa câu hỏi của tôi làm cho nó giống như tôi sẽ hỏi về byte và hoàn nguyên sự làm rõ của tôi. Câu hỏi thực sự là về giao diện chúng ta sử dụng.
Người dùng

Có, các khối được liên kết thông qua con trỏ và do đó, nội dung tệp không phải được lưu trữ liên tục nhưng khi chúng được lưu trữ liên tục thì phần cứng có thể đọc khối sau khối mà không cần phải chậm lại. Nếu nó phải theo con trỏ theo con trỏ thì đầu đọc sẽ liên tục di chuyển. Đó là lý do tại sao phân mảnh giúp tăng tốc máy tính của bạn. Nó đặt các con trỏ khối cho các tệp trong các khối liền kề. Sau đó, lệnh không đọc khối 1, đọc khối 3, đọc khối 9, đọc khối n ... nó trở thành đọc khối 1 đến n. Phần cứng có thể làm điều đó nhiều, hiệu quả hơn nhiều.
Dunk

12

Về mặt lý thuyết, bạn có thể thực hiện một tệp cho phép loại điều này. Tuy nhiên, để linh hoạt tối đa, bạn cần lưu trữ một con trỏ tới byte kế tiếp cùng với mỗi byte trong tệp. Giả sử một con trỏ 64 bit, điều đó có nghĩa là 8 trên 9 byte tệp của bạn sẽ bao gồm các con trỏ bên trong. Vì vậy, sẽ mất 9000 byte không gian để lưu trữ 1000 byte dữ liệu thực tế. Đọc tệp cũng sẽ chậm vì bạn cần đọc từng byte, đọc con trỏ, theo con trỏ để đọc byte tiếp theo, v.v. thay vì đọc các khối dữ liệu lớn, liền kề từ đĩa.

Rõ ràng, cách tiếp cận này không thực tế. Tuy nhiên, bạn có thể chia tệp thành các khối 32 kb. Điều đó sẽ giúp việc thêm 32 kb dữ liệu vào bất kỳ ranh giới 32 kb nào trong tệp tương đối dễ dàng. Sẽ không dễ dàng hơn khi thêm một byte đơn làm byte thứ 5 của tệp. Tuy nhiên, nếu bạn dành một số không gian trống trong mỗi khối, bạn có thể cho phép bổ sung dữ liệu nhỏ, điều này chỉ ảnh hưởng đến dữ liệu trong khối đó. Tất nhiên, bạn sẽ bị phạt về kích thước tệp, nhưng có khả năng là hợp lý. Tuy nhiên, việc tìm ra bao nhiêu không gian để dự trữ và cách phân chia các khối có xu hướng dễ dàng hơn cho một ứng dụng cụ thể so với hệ thống có mục đích chung-- những gì hoạt động trong một ngữ cảnh có thể rất tệ trong một bối cảnh khác tùy thuộc vào quyền truy cập tệp và đặc điểm sửa đổi.

Trên thực tế, nhiều hệ thống dành nhiều thời gian để tương tác với các tệp thực hiện một cái gì đó giống như những gì tôi đã mô tả ở trên khi chúng thực hiện trừu tượng hóa tệp cụ thể của chúng. Ví dụ, cơ sở dữ liệu sẽ triển khai một số khái niệm về "khối" là đơn vị I / O nhỏ nhất mà chúng có thể làm việc và thường sẽ dành một lượng không gian cho sự tăng trưởng trong tương lai để việc cập nhật một hàng trong bảng chỉ ảnh hưởng đến một khối mà dữ liệu đó được lưu trữ thay vì ghi lại toàn bộ tệp. Các cơ sở dữ liệu khác nhau, tất nhiên, có các triển khai khác nhau với sự đánh đổi khác nhau.


3
Tôi cũng đề cập đến thử thách "tìm kiếm khối ở mức 1 gigabyte của tệp 2 gigabyte" có thể mất một chút thời gian với danh sách thực hiện byte được liên kết.

Vấn đề của những gì xảy ra trong quá trình chèn là một nguyên nhân gây ra nhiều sự bối rối trong số những người thiết kế khử trùng lặp cho các hệ thống lưu trữ.
Blrfl

Cảm ơn vì đã hiểu rằng tôi không có ý nói về byte mà là về bức tranh lớn hơn.
Người dùng

8

"Vấn đề" nắm rõ cách các tệp được ghi ra phương tiện lưu trữ theo kiểu byte theo byte.

Trong biểu diễn cơ bản nhất của nó, một tệp không có gì khác ngoài một chuỗi các byte được ghi ra đĩa (còn gọi là phương tiện lưu trữ). Vì vậy, chuỗi ban đầu của bạn trông giống như:

Address  Value
0x00     `a`
0x01     `a`
0x02     `a`
0x03     `b`
0x04     `d`
0x05     `d`
0x06     `d`

Và bạn muốn chèn Cvào vị trí 0x04. Điều đó yêu cầu chuyển byte 4 - 6 xuống một byte để bạn có thể chèn giá trị mới. Nếu bạn không, bạn sẽ ghi đè lên giá trị hiện tại là 0x04 không phải là điều bạn muốn.

Address  Value
0x00     `a`
0x01     `a`
0x02     `a`
0x03     `b`
0x04     `C`
0x05     `d`
0x06     `d`
0x07     `d`

Vì vậy, lý do tại sao bạn phải viết lại phần đuôi của tệp sau khi bạn chèn một giá trị mới là vì không có bất kỳ khoảng trống nào trong tệp để chấp nhận giá trị được chèn. Nếu không, bạn sẽ viết quá nhiều những gì đã có.


Phụ lục 1 : Nếu bạn muốn thay thế giá trị bbằng Cthì bạn không cần phải viết lại phần đuôi của chuỗi. Thay thế một giá trị bằng một giá trị có kích thước tương tự không yêu cầu viết lại.

Phụ lục 2 : Nếu bạn muốn thay thế chuỗi abbằng Cthì bạn sẽ cần phải viết lại phần còn lại của tệp khi bạn đã tạo một khoảng trống trong tệp.

Phụ lục 3 : Cấu trúc cấp khối đã được tạo để giúp xử lý các tệp lớn dễ xử lý hơn. Thay vì phải tìm không gian liền kề có giá trị 1M cho tệp của bạn, giờ đây bạn chỉ cần tìm các khối có sẵn trị giá 1M để ghi vào thay thế.

Về lý thuyết, bạn có thể xây dựng một hệ thống tập tin thực hiện liên kết từng byte tương tự như các khối cung cấp. Sau đó, bạn có thể chèn một byte mới bằng cách cập nhật thành | từ con trỏ tại điểm thích hợp. Tôi sẽ mạo hiểm đoán rằng hiệu suất trên đó sẽ khá kém.


Như Grandmaster B đã đề xuất , hãy sử dụng hình ảnh của domino xếp chồng để hiểu trực quan cách tệp được biểu diễn.

trò chơi domino

Bạn không thể chèn một domino khác trong dòng domino mà không khiến mọi thứ sụp đổ. Bạn phải tạo không gian cho domino mới bằng cách di chuyển những người khác xuống dòng. Di chuyển domino xuống dòng tương đương với việc viết lại đuôi của tệp sau điểm chèn.


Giả sử ab C và d không phải là ký tự mà là gigabyte ký tự. Bạn có thể giải quyết điều này trong câu trả lời của bạn? Tôi thích hình ảnh này nhưng tôi cũng nghĩ mọi người sẽ chen vào chèn 1000 domino vào 2000 domino khác nhau mà 1 domino thành 6 domino.
Người dùng

@ Người dùng - GB ký tự thay vì byte thay đổi căn bản bản chất câu hỏi của bạn và bây giờ các khối để lưu trữ phải được xem xét. Ở mức độ đơn giản, câu trả lời là như nhau. Bạn không thể chèn một cái gì đó trong một loạt các "whatevers" liền kề mà không tạo không gian.

0

Việc chèn vào một tệp không được triển khai trong hầu hết các hệ thống tệp vì nó được coi là một hoạt động "tốn kém" (ăn thời gian và không gian) với các hậu quả "tốn kém" dài hạn và các chế độ thất bại bổ sung.

Một hệ thống tệp có ngữ nghĩa chèn có thể sẽ sử dụng shift & insert (có thể rất tốn kém khi bạn chèn ở phía trước một tệp lớn, nhưng không có / vài tác dụng phụ dài hạn) hoặc một số loại phân bổ heap tổng quát với kích thước phân bổ chiều dài thay đổi ( hiệu suất rất tệ trong một số trường hợp [hãy tưởng tượng khuôn mặt của người dùng tương tác nếu họ cố lưu tệp trong một GC dừng lại trên thế giới!]).

Nếu bạn muốn thử nghiệm, bạn có thể dễ dàng xây dựng một bản tóm tắt I / O trong Java hoặc Python thực hiện việc chèn. Nếu bạn thành công và nó có đặc điểm hiệu suất hoạt động tốt, bạn có cơ sở cho một bài nghiên cứu xuất sắc. Chúc may mắn.


điều này dường như không cung cấp bất cứ điều gì đáng kể so với 6 câu trả lời trước
gnat

Bạn có thể viết tất cả phần mềm bạn muốn nhưng nó sẽ không thay đổi cách thức hoạt động của phần cứng. Phần cứng hoạt động bằng cách đọc / viết trong khối / trang. Trong ổ cứng, nếu dữ liệu đó không liền kề thì đầu đọc phải di chuyển làm chậm đáng kể thời gian truy cập tệp. Bất kỳ thao tác chèn nào cũng sẽ "bởi thực tế nó là một phần chèn" phải được lưu trữ ở nơi khác và không được liền kề. Vì vậy, chắc chắn, chèn sẽ có thể nhanh hơn (đối với các tệp rất lớn) nhưng đọc sẽ chậm hơn nhiều.
Dunk

0

Cách hiệu quả nhất để chèn một khối byte vào giữa tệp sẽ là:

  1. Ánh xạ tệp vào bộ nhớ
  2. Nối các byte vào cuối hình ảnh bộ nhớ của tệp
  3. Xoay các tệp này vào vị trí (ví dụ: với một thuật toán tiêu chuẩn có sẵn trong Thư viện chuẩn C ++)
  4. Hãy để HĐH xử lý việc ghi các khối bẩn vào đĩa

-1

Trước tiên, bạn cần đọc mọi thứ sau điểm chèn, sau đó viết lại xuống nhiều khoảng trống như bạn sẽ chèn. Sau đó, bạn có thể viết dữ liệu "chèn" của mình vào đúng chỗ. Hoạt động cực kỳ kém, do đó không được hỗ trợ.


1
Điều gì tiếp tục một SSD với truy cập ngẫu nhiên? Ngoài ra các tập tin được chia thành từng phần bởi hệ thống tập tin. Làm thế nào mà liên quan đến việc viết lại mọi thứ?
Người dùng

@ Người dùng chắc chắn bạn có thể truy cập ngẫu nhiên (mặc dù bạn không thực hiện truy cập cấp bit, bạn vẫn đang thực hiện cấp khối) ... nhưng làm thế nào để bạn nói byte nào tiếp theo?

1
SSD vẫn đọc và viết một trang tại một thời điểm. Vì vậy, để viết 1 byte mà bạn muốn chèn, bạn phải ghi toàn bộ trang dữ liệu cùng với việc cập nhật tất cả các bảng / con trỏ hệ thống tệp tương ứng. Tôi sẽ không ngạc nhiên nếu các hệ thống tập tin ban đầu có hoạt động giống như chèn nhưng họ nhận ra rằng nó đã bổ sung nhiều chi phí hơn nhiều so với lưu.
Dunk

-1

Khi bạn truy cập trực tiếp vào một tệp bạn đang sử dụng ở mức thấp có thể được sử dụng để xây dựng các cấu trúc tinh vi hơn. Xem xét việc xây dựng cơ sở dữ liệu với dữ liệu của bạn cho phép các loại quyền truy cập bạn cần, bao gồm cả chèn.

Sẽ ít tốn kém hơn nếu bạn chỉ cần lặp qua tệp không truy cập ngẫu nhiên vào phần bù được chỉ định. Nếu bạn cần truy cập ngẫu nhiên bằng offset trong tệp, bạn sẽ cần cập nhật chỉ mục cho tất cả các byte ngoài điểm chèn.

Nói chung, bạn sẽ trả tiền trong việc lập chỉ mục cấu trúc dữ liệu, bộ nhớ để lưu chỉ mục và truy cập đĩa bổ sung để cập nhật nó.

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.