원시 바이트를 파일에 쓰는 데 위험이 있습니까? [닫은]


12

Programming Pearls의 문제, 특히 최대 10,000,000 개의 정수 (컬럼 1, 문제 3)를 포함하는 파일을 정렬하는 프로그램의 구현에서 문제를 겪고 있습니다. 이 책은 파일에 데이터를 저장하는 방법을 지정하지 않기 때문에 정수를 원시 바이트로 저장하는 것을 고려하고 있습니다 (원시 바이트를 좋은 옵션으로 만드는 다른 제약 조건이 있습니다). 나는 이전에이 낮은 수준에서 일한 적이 없으므로 조심해야 할 위험한 것이 있는지 알고 싶습니다. 예를 들어, 원시 바이트를 파일에 쓸 때 일종의 파일 끝 시퀀스를 실수로 사용하는 것에 대해 걱정해야합니까?

편집하다:

나는 지금 내 질문이 얼마나 광범위했는지 알고 있습니다. 실수로 디스크의 다른 파일을 덮어 쓰는 것과 같이 좀 더 치명적인 문제를 의미했습니다. 원래 명확하지 않은 죄송합니다.


6
Programming Pearls는 매우 오래된 책입니다. 현대 데스크탑 컴퓨터에서 10 ^ 7 정수 전체를 메모리로 쉽게 읽고 정렬하고 다시 쓸 수 있습니다. 해당 장의 원래 요점을 얻으려면 언제든지 읽는 양을 총 수의 일부로 제한하십시오. 또는 파일 크기를 약 10 ^ 10 정수로 늘리십시오.
Caleb

3
실제로, "위험한"이라는 단어를들을 때 PC가 폭발하거나 은행 계좌 등이 삭제되는 것을 생각합니다. 그리고 여러분의 프로그램이 에어 버스 나 발전소를 제어하는 ​​데 사용되지 않는 한, 당신이 생각하고있는 것을 시험해 볼 때 실제로 "위험한"일은 일어나지 않을 것이라고 가정하는 것이 가장 안전하다고 생각합니다.
Doc Brown


2
@delnan 몇 년 전, EOF 캐릭터의 신화가 유행했을 때, 나는 당시 많은 카피 프로그램이했던 'EOF 캐릭터까지 복사'를 기반으로 한 복사 방지 시스템을 회상합니다. 일부 프로그램은 관련 텍스트 파일의 EOF 표식 이후 , 그러나 파일의 할당 된 끝 전에 확인할 추가 데이터를 넣습니다 . 복사 프로그램은 새로 설치를 확인하는 추가 데이터를 복사하지 않습니다 ... 아아 ... 향수.

위험? "내가 이렇게하면 컴퓨터가 고장 날까?"처럼 아니.
jwenting

답변:


11

당신이 겪게 될 유일한 위험은 작은 대 큰 엔디안입니다 (가장 중요한 바이트가 가장 먼저 쓰여지는지 여부). 그러나 동일한 환경에 남아 있으면 문제가 없습니다. 글쓰기 / 구문 분석의 일반적인 보장 외에.

파일 시스템은 모든 바이트 시퀀스를 처리하도록 설계되었습니다.


2
마지막 줄에 +1 크고 작은 문제가 유일한 문제 인지 확실하지 않습니다. 예를 들어 OP는 정수 사이의 경계가 어디에 있는지 혼동 될 수 있습니다. 그러나 어쨌든 좋은 대답입니다.
Caleb

27

아니요, 실제로 이것은 몇 개의 파일 형식이 작동하는지입니다. 이와 같은 이진 파일의 일반적인 예로는 이미지 및 음악 / 오디오 파일이 있습니다.

파일과 파일에서 읽은 데이터의 무결성을 유지하려면 다음 지침을 따르십시오.

  • 항상 같은 모드 (텍스트 또는 이진)를 사용하여 파일 (읽기 또는 쓰기)을 엽니 다. 주요 차이점은 텍스트 모드가 줄 바꿈을 처리한다는 것입니다. 사용중인 특정 라이브러리에 따라 파일을 읽을 때 줄 바꿈 문자를 "숨길"수 있습니다. 텍스트 모드는 유니 코드가 아닌 데이터를 질식시킬 수있는 유니 코드 변환을 수행 할 수도 있습니다.
  • 문자열이 아닌 데이터를 읽을 때 쓰는 것과 동일한 데이터 유형을 사용하여 읽으십시오. 예를 들어, 파일의 처음 4 바이트가 설명 정수인 경우, 정수를 가져 오거나 제공하여 일관성있게 처리되도록하는 메소드를 사용하여 읽고 쓰십시오. 동일한 데이터 유형은 다른 머신에서 크기가 다를 수 있으며 동일한 머신에서 데이터 유형을 혼합하면 데이터의 의미를 변경할 수도 있습니다 (예 : 더 긴 정수 중간의 비트를 부호 비트로 해석).
  • 엔디안 : 사용중인 라이브러리가이를 일관되게 처리하지 않으면 직접 처리해야합니다. 예를 들어, Java는 항상 멀티 바이트 유형에 네트워크 바이트 순서 (빅 엔디안)를 사용합니다. C 및 C ++는 일반적으로 프로세서 (Intel의 리틀 엔디안, 대부분의 다른 엔디안)와 동일하게 라이브러리 구현자가 결정한 모든 것을 사용합니다. 이것이 하나의 시스템에서 빠른 연습 인 경우 중요하지는 않지만 필요한 경우이 문제에주의를 기울이고 코드를 작성하는 것이 여전히 좋은 습관입니다.

구체적인 세부 사항은 프레임 워크, 플랫폼 및 언어에 따라 다르지만 파일 I / O가 포함 된 기본 "gotchas"를 다루어야합니다.


3
문자열이 아닌 데이터에 대한 추가 사항 : 각 유형에 대해 일관된 바이트 수를 사용해야합니다. C 및 C ++에서 an int은 2-8 바이트 이상의 바이트 일 수 있습니다 (실제로 옥텟).
Bart van Ingen Schenau

그것은 내 두 번째 포인트에 내재적으로 포함되어 있습니다 (예 : 32 v. 64 비트 정수). 그것들은 다른 데이터 타입이 될 것입니다.

명시 적으로 만들 수도 있습니다. int서로 다른 두 시스템에서 다른 데이터 유형으로 간주 될 수 있음 은 분명하지 않습니다 .
Bart van Ingen Schenau

9

이미 언급 한 모든 문제 외에도 기존 형식으로 데이터를 읽고 쓰지 않고 새로운 이진 파일 형식을 구성하는 경우 파일 헤더 ( 처음에는 데이터 블록) 를 포함해야 합니다 . 파일 형식을 명확하게 식별하고 필요할 수있는 모든 메타 데이터를 기록합니다.

좋은 파일 헤더에는 최소한 세 가지가 포함됩니다.

  • 4 바이트 이상의 " 마법 번호 " 매직 넘버는 반드시 rfc2119 가 파일의 첫 N 바이트 여야 하며, 파기 할 수있는 다른 파일 형식에 사용 된 적이 없어야하며 인쇄 가능한 ASCII 문자가 아닌 적어도 하나의 바이트를 포함해야합니다. 매우 철저한 매직 넘버 를 디자인하는 방법 은 PNG 사양 을 참조하십시오 . 찾을 수있을만큼 포괄적 인 기존 매직 번호 데이터베이스 에 대해서는 명령 소스 코드를 참조하십시오 .file(1)

    매직 넘버의 요점은 파일을 대역 내 형식으로 명확하게 레이블링하는 것입니다. 매직 넘버를 포함하지 않거나 파일에서 첫 번째가 아닌 경우 파일을 다른 유형의 파일 로 잘못 인식하는 프로그램의 위험이 있으므로 데이터 손실, 바이러스 탈출 탐지 및 기타 재앙.

  • 파일 형식 의 버전 을 나타냅니다 . 당신은 당신이 결코 마법의 번호 뒤에 다음의 2 바이트가 될 수 있도록 획기적으로 파일 형식을 수정해야 할 것없는 것 같아요하더라도 00 00이 당신이 좋아하는 중 어떤 명확한 엔디 언의 16 비트 버전 번호가 (라고 및 문서 만 선택 하나의 파일 전체에 붙여 넣고 후속 데이터의 의미가 크게 바뀌면 증가합니다. 미래의 자기 자신이 감사합니다.

    (PNG 사양은 여기에서 다른 형식을 취하여 청크 형식이 고정되고 형식에 대한 모든 향후 변경 사항이 새로운 청크 형식의 형식을 취하도록 지정합니다. 또한 유효하지만 간단한 매직 숫자 + 버전 번호 접근 방식을 권장합니다. 이진 데이터 처리 초보자부터 PNG를 디자인 한 사람들은 수십 년 동안 이미지 형식에 대한 경험을 쌓았습니다.)

  • 파일에 임의의 메타 데이터 를 포함시키는 일종의 메커니즘 . 이는 다음 2 바이트가 헤더의 끝에서 실제 데이터의 시작까지 16 비트 오프셋이되는 것처럼 간단 할 수 있으며 사이의 모든 것은 UTF-8 키-값 쌍으로 해석됩니다. (즉, " Tag: value\n"—이 경로를 사용하는 경우 긴 줄을 접지 않는 것이 좋습니다 .) 다시 말하지만 PNG는 훨씬 더 영리합니다.


자신의 파일 형식을 만들 필요가 없습니다. 데이터를 이미지로 저장하면됩니다. 지원되도록 차원을 변경해야 할 수도 있습니다 (예 : 10k x 1k). 또는 FITS를 사용할 수 있습니다 . 데이터가 단일 어레이보다 복잡한 경우 HDF , CDF 또는 NetCDF를 사용할 수 있습니다 .
Joe

간단하게 유지하는 것이 좋습니다. 256 개의 다른 버전으로 충분하고 그렇지 않은 경우 추가 버전을 버전 255의 하위 버전으로 고안 할 수 있습니다. 메타 데이터와 마찬가지로 실제로 필요할 때 버전에 추가하면 충분합니다. @ 조 이미지? 모든 사람을 미리 혼동하여 잠재적 인 형식 혼란을 피하고 있습니다!
maaartinus

@maaartinus 버전 필드를 2 바이트로 만들면 형식 디자이너가 미리 엔디안을 커밋합니다. 메타 데이터를위한 공간은 항상 이진 형식의 버전 0이어야합니다. 그렇지 않으면 ID3과 같은 끔찍한 문제가 발생합니다. 형식 버전 범프 대신 새로운 청크 유형을 통한 확장성에 관한 PNG 사양의 논리에 대해 많은 동정심을 가지고 있습니다. 그러나 청크 구조 파일은 자체적으로 많은 복잡성을 초래하므로 간단한 경우에 권장하는 것을 주저합니다. 나는 의 이미 이러한 문제를 많이 처리하는 일반적인 형식으로 HDF를 추천하고 싶어.
zwol

2

아키텍처마다 정수에 대한 표현이 다릅니다. 여기에 주요 위험은 다시 읽으려고 다음 시스템 A의 정수의 바이트 표현을 저장하고 정수로 내용 및 해석 기계 A와 B 및 / 또는 다른 정수의 크기가 다른 경우 기계 B의를 엔디 언 , 당신 '을 정의되지 않은 동작 (예 : C) 또는 예외가 발생할 수 있습니다.

이것은 실제 예제가 아니라 프로그래밍 예제 일 뿐이므로 실제로 문제가되지는 않습니다. 이것이 실제 프로그램 인 경우, 고유 한 응용 프로그램 별 이진 형식을 롤링하는 것은 일반적으로 좋은 생각이 아닙니다. SQLite와 같은 더 나은 솔루션이나 JSON, YAML, XML 등과 같은 문자열 기반 직렬화 형식이 있습니다. 단일 값의 경우 문자열로 바꾸면 충분합니다. 간단한 목록의 경우 한 줄에 하나의 문자열을 저장하고 다시 읽을 때 줄 바꿈으로 입력을 분할 할 수 있습니다.


일반적으로 동의하지만 JSON 또는 XML은 10 ^ 7 숫자를 포함하는 파일의 크기를 크게 증가시킵니다. 또한 일반적으로 한 번에 모두 읽고 파싱하지만 문제의 장은 사용 가능한 메모리에 넣을 수있는 것보다 많은 데이터를 포함하는 파일을 정렬하는 방법을 다룹니다.
Caleb

그것은 당신이하는 일에 달려 있습니다. 때때로 SQL과 롤-자체의 성능 저하가 중요합니다. 내가 마지막으로 그것을했을 때 나는 작은 기록을 가지고 있었고 이웃을 원할 가능성이 높았습니다. 디스크에서 더 큰 블록을 읽는 것은 일반적으로 거의 비용이 들지 않으므로 하나의 레코드를 원한다면 1000을 캐시로 읽습니다. 내 기록은 거의 확실하게 서로 옆에 있었고 SQL을 사용하면 디스크 헤드가 모든 곳에서 튀어 나옵니다.
Loren Pechtel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.