190 likes | 401 Views
전북대 전자정보공학부 장 재 우 교수. Chapter 4. Fundamental File Structure Concepts. 1. 필드와 레코드 구성. (1) 스트림 화일 (Stream Files) 정보를 바이트 (byte) 의 스트림으로 표기. 입력. Mary Ames Alan Mason 123 Maple 90 Eastgate Stillwater, OK 74075 Ada, OK 74820.
E N D
전북대 전자정보공학부 장 재 우 교수 Chapter 4. Fundamental File Structure Concepts
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
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
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
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 • (3) 필드(field)의 스트림 판독 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
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
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
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
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
수의 십진수 값 바이트 내에 저장된 16진수 값 ASCII 문자형태 4 0 (a) ASCII 문자로 저장된 40 40 34 30 00 28 ‘\0’ ‘(‘ (a) 2-바이트 정수로 저장된 40 40 Field and Record Organization • 레코드 길이 표현하기 : 레코드 구조 방법(3) • 2바이트 이진 정수(binary integer) • 문자형태로 변환할 필요 없음 : C에서 사용 • ASCII 형태보다 큰 숫자를 표현가능 • 화일에서 문자가 아닌 부분을 해석하는 방법 필요 • 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 • VariableLengthBuffer • FixedFieldBuffer • 부록 F 에 전체 클래스 및 메소드가 수록 E-mail : jwchang@chonbuk.ac.kr
IOBuffer 버퍼값에 대한 문자 배열 VariableLengthBuffer 가변길이 레코드에 대한 판독/기록 연산 FixedLengthBuffer 고정길이 레코드에 대한 판독/기록 연산 DelimitedFieldBuffer 구분된 필드에 대한 팩/언팩 연산 LengthFieldBuffer 길이기반 필드에 대한 팩/언팩 연산 FixedFieldBuffer고정길이 필드에 대한 팩/언팩 연산 3. Using Inheritance for Record Buffer Classes • 레코드 버퍼 객체를 위한 클래스 계층 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