[c++]파일읽기를 할때에 파일의 일부분만을 메모리로 읽어오는

gyxor의 이미지

#include<iostream>
#include<fstream>
using namespace std;
int main(){ 

fstream file("data.txt",ios::in); 
//-data.txt- 
//abcdefh... char data[100] = {0}; 
  file.read(data,2);    
  cout << file.tellg(); 
  return 0;
}

위 소스에서는 전체 파일을 메모리(파일스트림)로 가져온뒤에
그중에 2개의 char를 읽었습니다.
따라서 파일포인터는 2가 되었습니다.

그런데
fstream file("data.txt",ios::in);위 함수에서 처럼 파일을
통째로 메모리로 가져오지 않고..

예를 들어(이런 함수는 없지만...)
fstream file("data.txt", ios::in ,100 ,200); 처럼
파일의 일부분만을 선택해서 가져오는 방법은 없나요?

답변부탁드립니다.

ps : C,C++책의 파일처리 부분을 다 찾아 봤는데요..
일단 파일전체를 메모리상으로 가져온뒤 그 내용중에서
선택하는 seek()등..의 함수뿐이었습니다.

체스맨의 이미지

C++ 의 fstream이나, C 의 fopen 모두 파일을 통째로 메모리에
올리지 않습니다. 파일의 일부를 경유 버퍼 ( intermediate buffer )에
올려두어서, 작은 크기의 데이터를 반복적으로 입출력하는 경우에
대해 속도를 향상시킵니다. 경유버퍼는 플렛폼에 따라 대개
수백~수천 바이트 정도 밖에 되지 않습니다.

파일 관련 표준 함수 중에 파일을 통째로 메모리에 올려서 입출력하는 것은
없습니다. 그 메모리와 파일의 일부만 입출력하면되는 경우 속도상의
비효율을 어찌 감당하라구요.

찾아보신 seek 관련 함수로 필요한 것을 구현하실 수 있을 것 같네요.

Orion Project : http://orionids.org

gyxor의 이미지

제가 시스템 버퍼에 관해서 잘 못 알고 있었습니다.
ifstream file("data.txt",ios::in);
file.seekg(64000);
file.read(...)
하게 되면 하드디스크의 64000위치에 해당하는 섹터를 찾아서
시스템 버퍼로 가져온뒤에 다시 메모리로 읽어오는..
디스크제어기-> I/O processor -> 메모리(시스템 버퍼) -> 메모리
과정을 잘못이해했었습니다.

첫째,
그런데 시스템 버퍼의 사이즈는 듣기로..
부팅시에 설정내용이 들어있는
하드디스크의 sector 0번지의 설정내용에서 클러스터사이즈부분
ex> 2*18*80 ;Number of sectors
에 의해서 셋팅이 되는것이라고 하던데요..
검증을 못해봤습니다.
자료를 찾아보니 4096바이트가 디폴드값이 라고 하는거 같기도 하구요
이 사이즈를 조절 하려면 어떻게 해야하는지 궁금합니다.

둘째,
만약 읽기가 아니라 쓰기라면 쓰고자하는 위치를 포함하는 섹터가
시스템 버퍼 상에 위치해야 하는데요
그렇다면 쓰는경우엔
파일 포인터 해당위치를 포함하는 섹터를 일단 시스템 버퍼로 불러온뒤에
그섹터 내용일부분에 저장을 하고나서 시스템 버퍼의 섹터내용을 디스크로
저장하게 되는것인가요?
예>

	ofstream file("data.txt",ios::out);
	file.seekp(30000);
	file.write("data",4);

이러한 경우에요..
내부 알고리즘이 어떤식으로 되는지 궁금합니다.

두가지 답변부탁드립니다.

bw001730의 이미지

첫째는 잘 모르겟습니다.
둘째것만 아는대로 .......말해보겠습니다.

둘째, 
만약 읽기가 아니라 쓰기라면 쓰고자하는 위치를 포함하는 섹터가 
시스템 버퍼 상에 위치해야 하는데요 
그렇다면 쓰는경우엔 
파일 포인터 해당위치를 포함하는 섹터를 일단 시스템 버퍼로 불러온뒤에 
그섹터 내용일부분에 저장을 하고나서 시스템 버퍼의 섹터내용을 디스크로 
저장하게 되는것인가요? 

제가 아는대로 간략히 적어보면

1. a.out 실행

2. 프로세스 생성됨
    커널이 프로세스를 관리하기 위해
     사용되는 구조체인 struct task_struct 할당됨

    struct task_struct
    {
          struct file *descripter_list[];
          // .................
    }
    descripter_list의 0,1,2는 기본적으로 할당됨
(지금은 더 많이 오픈할수 잇지만  
예전엔 1024크기로 고정되어서
파일을 1024개 밖에 열수 없었습니다.)

이제 fopen 등의 파일을 여는 함수를 호출하면 open() 시스템 콜이 동작합니다.

3. open
    struct file 할당됨
     
    struct file
    {
          int   access_mode;   // readonly,writeonly, append
          int   file_position;     // 파일의 어디까지 읽거나 썼는가
          //...........
    }
    이 구조체 포인터를 descripter_list[3] 에 저장함
    앞으로 파일을 읽거나 쓰면 descripter_list[3] 
     즉, 위 파일구조체를참조하게됨     

아직까지는 커널이 디스크를 접근하지는 않았습니다.

파일에 쓰는 것이니깐
write() 시스템 콜이 호출됩니다.

3. write()
write() 시스템 콜은 이런식으로 커널에 요청을 하게 됩니다.
a.txt 파일의 n 번째부터 100바이트 읽어라

커널이 디스크에서 한번에 1000씩 읽어온다면
디스크캐시는 1000의 블럭단위로 관리하게될겁니다.(실제론 아마도 4096일듯)
디스크 캐시에 있다면 디스크 캐시에 써라. 캐시에 있다고 가정하고.
이때 읽고자 하는 100바이트가 파일의 950~1050 사이였다면
두개의 블럭을 디스크로 부터 읽어와야 할것입니다.
(캐쉬에 있다면 그걸 사용하구요)
자..... 디스크에 쓰지 않고 캐쉬에 썼습니다.
즉시 디스크에 저장하는가? 하면 그렇지 않습니다. 디스크 속도문제겠죠
캐쉬에다가 플래그를 설정합니다. 
"이거는 아직 디스크에 쓰지 않았으니깐 나중에 반드시 디스크에 써넣어야대"
이런 의미입니다. 운영체제에서는 더티비트라고 합니다. 때가 묻었다 이거죠

갑자기 전원이 나가면 더티비트 설정된것들은 모두 잃어버리게 됩니다.
그래서 중요한 서버라면 ups사용합니다.

리눅스는 30분 간격으로 더티비트가 설정되어 있는 것을 일괄적으로
디스크에 써넣는다고 합니다. ps -aux 하면 kupdate 머 이런 이름으로 데몬이 떠 있는것을 확인할수 있습니다. 이 데몬이 그렇게 한다고 합니다.

또는 커널이 새로운 디스크에 대해 캐쉬를 할당해야 하는데
꽉차서 더이상 남는 것이 없으면 가장 오래된거를  사용합니다.
이때 오래된 캐쉬에 더티비트가 설정되어 있으면 디스크에 쓴담에
새로운 블럭을 할당합니다.

이런식으로 디스크에 쓰게 됩니다.

캐쉬에 다 썼으면 struct file 의 file_position += 100 을 해줍니다.

참고로 아이노드 얘기는 하지 않았습니다.
너무 깁니다.
참고한 커널구조체는 이름은 정확하지만 멤버변수들의 이름은 다릅니다.
기억못하고 찾아보기는 귀찬고 해서리. .........^^
대신 그런의미의 변수들은 분명히 있습니다.
Bach라는 분의 유닉스 운영체제의 설계
Unix Operating System 을 읽어보시길..권해드립니다.
또 advanced unix programing 을 참조하시길.....스티븐스

.. 님께서 말씀하신 시스템버퍼가 디스크 캐쉬인것 같네요

흑 너무 길당.....

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.