Chapter 4. Fundamental File Structure Concepts 전북대 전자정보공학부 장 재 우 교수
E-mail : jwchang@chonbuk.ac.kr 1. 필드와 레코드 구성 (1) 스트림 화일(Stream Files) 정보를 바이트(byte)의 스트림으로 표기 입력 Mary Ames Alan Mason 123 Maple 90 Eastgate Stillwater, OK 74075 Ada, OK 74820 A field is the smallest logically meaningful unit of information in file field contains a single data value 출력 AmesMary123 MapleStillwaterOk74075MasonAlan90 EastgateAdaOK74820 E-mail : jwchang@chonbuk.ac.kr
E-mail : jwchang@chonbuk.ac.kr 1. 필드와 레코드 구성 Definition of record to hold person information In C: struct Person { char last[11]; char first[11]; char address[16]; char city[16]; char state[3]; char zip[10]; }; In C++: class Person { public: char last[11]; char first[11]; char address[16]; char city[16]; char state[3]; char zip[10]; }; E-mail : jwchang@chonbuk.ac.kr
E-mail : jwchang@chonbuk.ac.kr 1. 필드와 레코드 구성 (2) 필드(field) 구조 방법 1 : 고정 길이 필드 필요한 최대 크기 배정 화일 크기가 커짐 길이가 다양한 필드를 포함하는 데이터에는 부적합 필드길이가 비슷한 경우 유용 방법 2 : 길이 지시자(length indicator) 필드의 앞에 필드의 길이를 저장 길이기반(length-based) 필드 어떻게 필드를 유지할 것인가? Ames Mary 123 Maple Stillwater OK74075 Mason Alan 90 Eastgate Ada OK74820 04Ames04Mary09123 Maple10Stillwater02OK0574075 05Mason04Alan1190 Eastgate03Ada02OK0574820 E-mail : jwchang@chonbuk.ac.kr
E-mail : jwchang@chonbuk.ac.kr 1. 필드와 레코드 구성 필드(field) 구조 방법 3 : 구분자(delimiter) 구분문자로 필드 식별 구분자 : 필드 내에 포함되지 않는 특수문자 방법 4 : 키워드(key word) 자체 기술적(self-describing)구조 : 화일 구성에 유용 구분자와 결합하여 사용 공간의 낭비 Ames|Mary|123 Maple|Stillwater|OK|74075 Mason|Alan|90 Eastgate|Ada|OK|74820 last=Ames|first=Mary|address=123 Maple|city=Stillwater| state=OK|zip=74075 E-mail : jwchang@chonbuk.ac.kr
Field and Record Organization istream & operator >> (istream & stream, Person & p) { // 화일로부터 구분자‘|’로 구분된 필드를 판독 char delim; stream.getline(p.LastName,30, ‘|’); if( strlen(p.LastName) == 0 ) return stream; stream.getline(p.FirstName, 30, ‘|’); stream.getline(p.Address, 30, ‘|’); stream.getline(p.City, 30, ‘|’); stream.getline(p.State, 15, ‘|’); stream.getline(p.ZipCode, 10, ‘|’); return stream; } < Person 객체에 구분된 필드를 판독하기 위한 추출 연산자 > E-mail : jwchang@chonbuk.ac.kr
E-mail : jwchang@chonbuk.ac.kr 1. 필드와 레코드 구성 (4) 레코드(record) 구조 방법 1 : 고정길이 레코드(fixed-length record file) 각 레코드가 같은 수의 바이트로 구성 필드 크기나 수를 고정하는 것은 아님 가변길이 필드를 위한 컨테이너로 사용 Ames Mary 123 Maple Stillwater OK74075 Mason Alan 90 Eastgate Ada OK74820 unused space Ames|Mary|123 Maple|Stillwater|OK|74075 Mason|Alan|90 Eastgate|Ada|OK|74820 E-mail : jwchang@chonbuk.ac.kr
E-mail : jwchang@chonbuk.ac.kr 1. 필드와 레코드 구성 레코드(record) 구조 방법 2 : 고정갯수 필드 각 레코드가 같은 수의 필드로 구성 6개의 필드가 하나의 레코드 형성 방법 3 : 길이 지시자(length indicator) 각 레코드는 길이 지시자를 지님 가변길이 레코드 처리에 널리 쓰임 Ames|Mary|123 Maple|Stillwater|OK|74075|Mason|Alan|90 Eastgate|Ada|OK|74820 40Ames|Mary|123 Maple|Stillwater|OK|74075|36Mason|Alan|90 Eastgate|Ada|OK|74820 E-mail : jwchang@chonbuk.ac.kr
E-mail : jwchang@chonbuk.ac.kr 1. 필드와 레코드 구성 레코드(record) 구조 방법 4 : 주소 index 사용 레코드의 시작 주소 (바이트 오프셋:offset) 를 인덱스를 사용 방법 5 : 구분자(delimiter) 사용 각 레코드의 끝에 구분자를 놓음 ‘#’ 를 구분자로 사용 Data file : Ames|Mary|123 Maple|Stillwater|OK|74075|Mason|Alan|90 Eastgate|Ada|OK|74820 Index file : 00 40 ……….. Ames|Mary|123 Maple|Stillwater|OK|74075|#Mason|Alan|90 Eastgate|Ada|OK|74820 E-mail : jwchang@chonbuk.ac.kr
E-mail : jwchang@chonbuk.ac.kr 1. 필드와 레코드 구성 (5) 길이지시자를 사용하는 레코드 구조 화일에 가변길이 레코드 구현에 대한 문제점 모든 레코드의 시작부분에 길이 지시자를 넣는다면, 화일에 레코드를 기록하기 전에 각 레코드의 필드 길이의 합을 알아야만 함 출력하기 전에 레코드의 전체 내용을 버퍼에 저장할 필요가 있음 Person Buffer (MaxBufferSize) Ames Mary 123 Maple Stillwater OK 74075 버퍼에 쓰기 Ames|Mary|123 Maple|Stillwater|OK|74075| Get Record Length 버퍼 내용을 파일에 쓰기 필드 구분자 ‘|’ 추가 레코드 길이 쓰기 File E-mail : jwchang@chonbuk.ac.kr
Field and Record Organization 화일에 가변길이 레코드 기록하기 : 레코드 구조 방법(3) const int MaxBuffeSize = 200; int WritePerson (ostream & stream, Person &p) { // 버퍼 생성 char buffer [MaxBufferSize]; // 각각의 필드에 구분자 ’|’를 덧붙여서 버퍼에 쓰기 strcpy(buffer, p.LastName); strcat(buffer, “|”); strcat(buffer, p.FirstName); strcat(buffer, “|”); strcat(buffer, p.Address); strcat(buffer, “|”); strcat(buffer, p.City); strcat(buffer, “|”); strcat(buffer, p.State); strcat(buffer, “|”); strcat(buffer, p.ZipCode); strcat(buffer, “|”); // 버퍼에 기록된 레코드 길이를 구하여 화일에 써 넣기 short length = strlen(buffer); stream.write (&length, sizeof(length)); // 버퍼에 기록된 레코드 내용을 화일에 써 넣기 stream.write (&buffer, length); } < 가변길이 레코드(Person 객체)를 화일에 쓰기 > E-mail : jwchang@chonbuk.ac.kr
Field and Record Organization 레코드 길이 표현하기 : 레코드 구조 방법(3) 2바이트 이진 정수(binary integer) 문자형태로 변환할 필요 없음 : C에서 사용 ASCII 형태보다 큰 숫자를 표현가능 화일에서 문자가 아닌 부분을 해석하는 방법 필요 ASCII 문자 34 30 00 28 (a) ASCII 문자로 저장된 40 (a) 2-바이트 정수로 저장된 40 40 ‘\0’ ‘(‘ 4 0 수의 십진수 값 바이트 내에 저장된 16진수 값 ASCII 문자형태 E-mail : jwchang@chonbuk.ac.kr
Field and Record Organization 화일로부터 다양한 길이 레코드의 판독 : 레코드 구조 방법(3) 디스크에 있는 화일의 레코드 판독 버퍼에 레코드를 저장 레코드를 필드로 분리 Person Buffer (length+1) Ames Mary 123 Maple Stillwater OK 74075 버퍼에서 읽기 Ames|Mary|123 Maple|Stillwater|OK|74075| 버퍼 생성 Get Record Length 레코드를 버퍼에 읽어 오기 필드 구분자 ‘|’ 제거 레코드 길이 읽기 File E-mail : jwchang@chonbuk.ac.kr
Field and Record Organization 화일로부터 다양한 길이 레코드의 판독 : 레코드 구조 방법(3) int ReadVariablePerson (istream & stream, Person & p) { // 화일에서 레코드 길이 읽기 & 버퍼 생성 short length; stream.read (&length, sizeof(length)); char *buffer = new char[length+1]; // 버퍼에 레코드 읽어 오기 stream.read (buffer, length); // 버퍼 내용을 문자열 타입으로 변환하여 operator>>() 함수를 사용할 수 있도록 함 buffer [length] = 0; // terminate buffer with Null istrstream strbuff (buffer); // operator>>() 함수를 호출하여, // 버퍼로부터 필드 구분자 ‘|’ 를 제거하고 각 필드를 Person 객체에 읽어 오기 strbuff >> p; return 1; } < 화일에서 가변길이 레코드(Person 객체) 읽기 > E-mail : jwchang@chonbuk.ac.kr
Field and Record Organization (6) 문자와 수의 혼합 : 화일 덤프 사용 Offset Values 0000000 \0 ( A m e s | M a r y | 1 2 3 0028 416d 6573 7c4d 6172 797c 3132 3320 0000020 M a p l e | S t i l l w a t e r 4d61 706c 657c 5374 696c 6c77 6174 6572 0000040 | O K | 7 4 0 7 5 | \0 $ M a s o 7c4f 4b7c 3734 3037 357c 0024 4d61 736f 0000060 n | A l a n | 9 0 E a s t g a 6e7c 416c 616e 7c39 3020 4561 7374 6761 0000100 t e | A d a | O K | 7 4 8 2 0 | 7465 7c41 6461 7c4f 4b7c 3734 3832 307c E-mail : jwchang@chonbuk.ac.kr
2. Using Classes to Manipulate Buffers 3개의 클래스 (1) 구분된 텍스트 필드를 위한 버퍼 클래스:DelimTextBuffer(구분자) (2) 길이기반 필드를 위한 버퍼 클래스: LengthTextBuffer(길이지시자) (3) 고정길이 필드를 위한 버퍼 클래스: FixedTextBuffer (고정길이필드) 부록 E 에 수록되어 있음 E-mail : jwchang@chonbuk.ac.kr
3. Using Inheritance for Record Buffer Classes 기초 클래스 : IOBuffer 각 메소드들은 virtual로 선언되어 자신의 구현을 서브클래스에서 정의할 수 있도록 함 VariableLengthBuffer DelimitedFieldBuffer LengthFieldBuffer FixedFieldBuffer 부록 F 에 전체 클래스 및 메소드가 수록 E-mail : jwchang@chonbuk.ac.kr
3. Using Inheritance for Record Buffer Classes 레코드 버퍼 객체를 위한 클래스 계층 IOBuffer 버퍼값에 대한 문자 배열 VariableLengthBuffer 가변길이 레코드에 대한 판독/기록 연산 FixedLengthBuffer 고정길이 레코드에 대한 판독/기록 연산 DelimitedFieldBuffer 구분된 필드에 대한 팩/언팩 연산 LengthFieldBuffer 길이기반 필드에 대한 팩/언팩 연산 FixedFieldBuffer 고정길이 필드에 대한 팩/언팩 연산 E-mail : jwchang@chonbuk.ac.kr
E-mail : jwchang@chonbuk.ac.kr HomeWork #2 입력 텍스트 화일(in.txt)을 읽어서, 길이지시자를 포함하는 가변길이 레코드를 구성하여 출력 화일(out.txt)을 생성한다. 생성된 출력화일(out.txt)로부터 레코드 정보를 읽어와서, 한 라인에 한 레코드씩 화면에 출력하는 프로그램을 작성하라. 레코드의 구성 학번(ST_NUM) 이름 (ST_NAME) 집전화 (PHONE) 휴대전화 (M_PHONE) 이메일(MAIL) 참조 레코드 정보 구성: Figure 4.2 in.txt 읽기: 고정길이 out.txt 출력: 가변길이 출력 Screen in.txt out.txt 학번1 이름1 집전화1 휴대전화1 이메일1 학번2 이름2 집전화2 휴대전화2 이메일2 : 학번10 이름10 집전화10 휴대전화10 이메일10 길이1학번1|이름1|집전화1|휴대전화1|이메일1|길이2학번2| 이름2|집전화2|휴대전화2|이메일2|...|길이10학번10|이름10| 집전화10|휴대전화10|이메일10| in.txt 화일은 http://dblab.chonbuk.ac.kr 에서 다운로드 제출 : melipion@chonbuk.ac.kr E-mail : jwchang@chonbuk.ac.kr