ㅅㅇ
python 프로그래밍 : 텍스트 파일 입출력 본문
_플레이데이터 빅데이터캠프 공부 내용
- 텍스트(입출력할 데이터 종류) 파일(입출력할 대상) 입출력 을 뜻한다.
1. 입출력 개요
경로란?
파일, 디렉토리 위치 -> 자원의 위치. 프로그램이 사용할 자원의 위치
경로 표현 방법
ROOT 디렉토리 : 시작 디렉토리
- 윈도우 -> C: , d:
- 리눅스, 유닉스 -> /
(1) 절대경로
- 시작 디렉토리부터 자원(파일, 디렉토리)의 위치를 표현한다.
- 시작 디렉토리 : root 디렉토리
- ex. 파일 경로 c:\class\p1.pdf 디렉토리 경로 c:\class\lib #윈도우
- 자원의 전체 경로를 경로를 표현하는 방식
- 장점 : 같은 데이터라면 항상 경로 고정 (오류 확률 낮다.) - 단점 : 길다
(2) 상대경로
- 현재 디렉토리(위치)로부터 찾아가는 경로 표현방식
- 시작 : 현재 디렉토리
- 장점 : 짧다 - 단점 : 같은 데이터라도 현 위치에 따라 경로가 다르다 (오류 확률 높다.)
- 구문
. : 현재 디렉토리
.. : 상위 디렉토리
윈도우즈 \ 리눅스 유닉스 / : 경로 구분자 -> 하위 계층으로 가라.
- ex. 현재 디렉토리 c:\class
.\p1.pdf => 현재(.)디렉토리의 하위 계층(\)으로 가라.
보통 .\은 생략한다. p1.pdf
- ex. 현재 디렉토리 c:\class
.\01_PYTHON\a.txt => 현 디렉토리의 하위 계층에서 파이썬 폴더의 하위계층에서 해당 파일을. 보통 .\은 생략한다. 보통 .\은 생략한다. 01_PYTHON\a.txt
- ex. 현재 디렉토리 c:\lntel\n => 현 디렉토리에서 나와서 다른 디렉토리로 가야 한다.
.\..\..\class\01_PYTHON\a.txt
보통 .\은 생략한다. ..\..\class\01_PYTHON\a.txt
** 경로구분자 만날 때 마다 그 해당 디렉토리에 들어간다고 생각하자. ** 계층구조 이해하기(이미지로 생각)
입출력이란?
- 프로그램이 외부 자원(파일...)에 데이터를 쓰거나(output 출력) 읽는(input 입력) 작업을 입출력(IO)라고 한다.
- 외부자원
: 데이터를 제공하는 것 : 파일, Database, 원격지 컴퓨터(네트워크로 연결된) 등
: 어떤 자원이냐에 따라 입출력 방식이 달라지지만 입출력 코딩 패턴(아래), 개념 자체는 동일하다.
코딩 패턴 : 1 파일 열기(연결) -> 2 데이터를 파일에 쓰기/읽기 -> 3 파일 닫기(열결 끊기)
file = open() -> file.write() / file.read() -> file.close()
- 파일열기, 데이터를 읽기쓰기는 예외상황이 있기 때문에 -> try에 넣는다.
- 파일 닫기(연결 끊기)는 무조건 일어나야 하는 작업 -> finally에 넣는다.
- 현재 내 프로그램을 위해 외부자원에서 내가 필요한 데이터 입력받고(read), 내부에 저장할 데이터를 출력(write)한다.
ex. 내가 만든 코드를 디렉토리 자원에 저장한다. -> Output / 하드디스크에 있는 받은 코드 파일을 읽어온다. -> Input / 작업 한다.(여기다가 쓴다고 출력이 아님. 저장을 해야.) /하드디스크에 수정한 파일을 저장한다. -> Ouput )
- 컴퓨터는 기계어 0과1 2진수만을 이해한다. 우리 작성한 name ="홍길동" 또한 기계어로 저장된다.
이때 데이터를 출력된다는 것은 바이트단위로 외부자원으로 흘러 가는 것. 프로그램과 외부자원이 통이 연결되고 그 통으로 데이터가 흘러가고 바이트 단위로
- Stream
: 데이터 입출력 흐름. 프로그램과 외부자원 사이 데이터가 흐르는.
입력(자원에서 프로그램으로 데이터가 흐르는) : InputStream
출력(프로그램에서 자원으로 데이터가 흐르는) : OutStream
입출흐름, 출력흐름 하는 것들이 있는데, 그것 하나만 가지고 이 흐름이 중복되거나, 왔다갔다 같이 할 수 없다.
한쪽으로만 흐르는 개념이다. 입력흐름이면 입력만, 출력흐름이면 출력만 흐름 하나가지고 둘 다 할 수 없다.
** 현재 경로 - workdirectory 경로 조회 방법
import os # os 모듈을 import
cwd = os.getcwd() # current work directory
print(cwd) # 상대경로의 현재위치가 된다. ( . )
2. TEXT 파일 입출력
- 문자열(string)을 입/출력 하는 것.
- 메모장으로 볼 수 있으면 text
- 모드 : 목적+데이터형식(t) => rt, wt
인코딩이란?
: 원본(내 데이터)를 일관된 형식으로 외부자원에 맞춰 변환하는 것.
==> 유니코드를 기반으로 인코딩 방식(실질적으로 처리하는 방식)의 다양한 종류가 있다.
- open 함수에서 encoding="" 인코딩방식을 다르게 넣을 수 있다.
- None일 경우 os 기본 인코딩 방식따름. 윈도우 "ANSI" 쥬피터 인코딩 "utf-8"
- 근데 utf-8로 출력하면 입력받을 때도 utf-8로 인코딩 방식을 맞춰서 해줘야 함.
남의 데이터를 입력받을 때도 해당 데이터의 방식을 알아내어 읽어줘야 한다.
- 우리가 "A"을 작성한다고 해서 그대로 저장되는 게 아님. 기계어 0과 1로 저장되어야 한다. 숫자 10진수는 2진수로 바꾸는 방법 우리가 안다. 그렇다면, 문자열을 이진수로 어떻게 바꾸냐? 약속한 표를 만들었다.
- ASC 코드 : 8bit로 정의한 코드 2\**8=256가 정의되어 있다.영문 알파벳을 사용하는 대표적인 문자 인코딩
- 근데 영어말고도 많은 언어를 표현할 수 있어야 한다. 그래서 Unicode를 만듦
- Unicode : 전 세계의 모든 문자를 일관되게 표현하고 다룰 수 있도록. 16bit
디코딩이란?
코드화된 내용을 원래의 정보로 변환하는 디코딩 작업
** UnicodeDecodeError : 잘못된 (저장된 인코딩방식과 다른) encoding 방식으로 읽을 경우 발생. 해당 파일의 인코딩방식으로 입력받아야 한다. ex) encoding=""
<출력하기 Write>
1) 연결하기 _ open() 함수 사용
: 연결된 파일과 입출력 메소드를 제공하는 객체(Stream)를 리턴
- open(file, mode, encoding) 상황에 따라 함수 주요 매개변수 넣어주기.
file : 연결할 경로
mode : 열기 모드 : 목적과 데이터종류를 조합해 나타낸다.
encoding : 해당 인코딩 표시. (None일 경우 OS 기본 encoding 방식을 따른다.)
- 목적 : 'r '읽기(기본값) 'w' 쓰기 'a' 이어쓰기(기본내용 두고)
- 데이터 종류 : 'b' 바이너리모드 't' 텍스트모드(기본값: 생략가능)
- 구문
fw = open(file_path, mode, encoding="utf-8")
=> '파일'과 '지정한 모드'에 맞춰서 연결하고 입출력할 수 있는 기능(메소드)를 제공하는 객체를 반환. 이것을 변수로 받아서 쓰면됨.
- 출력 연결의 경우에는 연결할 파일이 없으면 생성. 있으면 있는 파일과 연결 (단 데이터를 지운다.)
- 입력 연결의 경우에는 연결할 파일이 없으면 exception 발생. => 예외처리해주기. try except finally
EX. txt의 문자열데이터를 "현재작업경로\a.txt" 파일에 출력(저장)
# 출력 데이터
txt = """안녕하세요
반갑습니다.
오늘도 즐거운 하루되세요."""
print(txt)
# 1. a.txt와 연결: 목적-출력, 데이터종류-string(text)
# 상대 경로 # .\을 생략
file_path = "a.txt"
# 목적데이터종료
mode = "wt" # 목적: w 쓰기모드 데이터 :t 텍스트 모드 #t 기본값이라 안 써도 되지만 써주자.
fw = open(file_path, mode, encoding="utf-8")
# 파일과 지정한 모드에 맞춰서 연결하고 입출력할 수 있는 기능(메소드)를 제공하는 객체를 반환. 이것을 변수로 받아서 쓰면됨.
- 만약 절대경로로 표시한다면?
# file_path = r"C:\Users\ABC\a.txt" # 절대경로
# r붙이면 escape \ 처리 안 하게 # 유닉스 슬러시면 escape 아니라 상관없다.
2) 데이터쓰기 출력 _ 객체명.write(데이터)
fw.write(txt)
# 이때 출력값은 글자수이다.
3) 연결닫기 : 예외없이 얼어나야 함. _ 객체명.close()
fw.close()
<입력받기 Read>
1) 연결하기(파일열기) _ open() 함수 사용
fi = open("경로", "rt", encoding="utf-8")
# 목적 : 읽기 - r(기본값), 데이터 : string(text) - t(기본값)
2) 데이터읽기 입력 _ 데이터 받을 변수 = 객체명.Read()
r_txt = fi.read()
- 받아온 데이터를 변수에 저장
3) 연결닫기 _ 객체명.close()
fi.close()
i_file_path = "a.txt" # 상대경로
# 목적 : 읽기 - r(기본값), 데이터 : string(text) - t(기본값)
i_mode = "rt"
# 연결
fi = open(i_file_path, i_mode, encoding="utf-8")
# 입력 - read() 받아 변수에 저장
r_txt = fi.read()
print(r_txt)
# 3. 연결닫기
fi.close()
<연결 닫기 코드 예외처리 해주기 >
- 연결닫기는 무조건 실행해야 하는 코드
방법 1) try except finally 로 처리
# 예외처리 - "연결닫기 " finally 처리
try:
fi = open("a.txt", "rt")
t = fi.read() # 이 줄에서 오류난다면
print(t)
except:
print("처리") # 출력하고
finally:
print("연결닫기") # 이구문 반드시 하고
fi.close()
방법 2) with block 이거쓰기!
- with block을 빠져나오면 close를 자동으로 처리한다.
- 구문
with 연결함수 as 변수:
작업코드
- print(fi.closed) # 연결여부를 부울값으로 반환받아 체크할 수 있다. : True-끊는 것, False-연결상태
ex)
with open("a.txt", "rt", encoding="utf-8") as fi
EX. With block 예시
with open("a.txt", "rt", encoding="utf-8") as fi:
# fi = open(...)과 동일
# as 뒤에 객체 변수
# 입출력코드
try:
r = fi.read()
print(fi.closed) # 연결여부를 반환 : True-끊는 것, False-연결상태
print(r)
except:
print("예외처리")
print("with block 밖", fi.closed)
# with block을 빠져나오면! close를 자동으로 처리한다.
3. 출력 메소드
(1) fw.wirte("")
- 출력은 여러번에 걸쳐서도 할 수 있다.
- 작업하고 출력하고 작업하고 출력하고 가능한 것
- but, print와 달리 엔터처리 없음. 이어서 나옴. => \n 넣어줘야 함
- 출력가능한 타입은 string = > 다른 타입은 모두 str() 변환해줘야 한다.
with open("b.txt", "wt") as fw:
fw.write("안녕하세요\n")
fw.write("반갑습니다.\n")
fw.write("조금만 있으면 점심시간이네요.\n")
fw.write(30)
# 출력가능한 타입은 string!!
(2) 리스트 데이터를 출력
방법1 ) fw.writelines(txt_list)
: 리스트의 원소들을 한번에 출력
- 원소와 원소 사이가 엔터가 안되기 때문에 각 원소 사이에 \n을 넣어준 것이다.
EX. 리스트 출력 _ 메소드 fw.writelines(txt_list) 로
# EX. 리스트 출력 fw.
txt_list = ["안녕하세요.\n", "지금 12시 16분입니다.\n", str(120)]
with open("c.txt","wt") as fw:
fw.writelines(txt_list) # 리스트의 원소들을 한번에 출력 # 엔터 안 넣으면 한줄
방법2) 리스트 출력을 위 함수메소드 대신에 반복문으로 구현 가능하다.
# EX. 리스트 출력 _ for 문으로
txt_list = ["안녕하세요.\n", "지금 12시 16분입니다.\n", str(120)]
for t in txt_list:
fw.write(txt_list(i))
4. 입력 메소드
(1) fi.read() : 파일 데이터를 한번에 읽는다.
EX. 뉴스 news.txt 파일 읽기_fi.read()
news_file_path = 'text_data/news.txt'
with open(news_file_path, "rt", encoding="utf-8") as fi:
news = fi.read() # 파일의 전체내용을 한번에 읽는다.
print(news)
- 파일 내 엔터되있으면 엔터 되있는대로. 그냥 파일의 전체내용을 한번에 읽어 변수에 저장한다.
(2) 리스트 데이터를 입력 Read
방법1) fi.readlines()
: \n 엔터 기준으로 한 줄, 한줄을 원소로 하는 리스트를 반환.
- 잘 안 씀.
EX. 뉴스 news.txt 파일 읽기 _ 리스트에 넣어 읽기_메소드 fi.readlines()
# EX.뉴스 news.txt 파일 읽기 _ 리스트에 넣어 읽기
with open(news_file_path, "rt", encoding="utf-8") as fi:
text_list = fi.readlines() # \n 엔터 기준으로 한 줄, 한줄을 원소로 하는 리스트를 반환.
print(text_list) # 리스트 전체 출력
print("--------------")
print(text_list[0])
print(text_list[1])
print(text_list[2])
방법2) 리스트 출력을 위 함수메소드 대신에 반복문으로 구현 가능하다.
- 반복문을 이용해 한줄 씩 읽을 수 있다.
- rt모드로 연결한 객체(TextIOWapper)가 iterable
=> 직접 for in 문의 in 자리에 넣을 수 있다.
- read 메소드를 사용하지 않고 객체 자체를 바로 print 하는 것.
- read() fi 반복문. 이를 가장 많이 쓴다. 굳이 writelines 쓸 필요 없음.
EX. 뉴스 news.txt 파일 읽기 _ 리스트에 넣어 읽기_ for문으로
# EX.뉴스 news.txt 파일 읽기
# read() fi 반복문. 이를 가장 많이 쓴다.
# 그래서 굳이 writelines 쓸 필요 없음.
with open(news_file_path, "rt", encoding="utf-8") as fi:
for ln, txt in enumerate(fi,start=1):
print(f"{ln}.{txt}")
1.아스널 레전드가 극찬한 공격수, ‘SON 파트너’로 부상
2.토트넘 홋스퍼가 손흥민(29), 해리 케인(28) 파트너를 찾았다.
(3) fi.readline()
# 한줄씩만 읽는다. 읽고 그 다음 줄
with open(news_file_path, "rt", encoding="utf-8") as fi:
print(fi.readline()) #한줄만 읽는다.
print(fi.readline())
아스널 레전드가 극찬한 공격수, ‘SON 파트너’로 부상
토트넘 홋스퍼가 손흥민(29), 해리 케인(28) 파트너를 찾았다.
5. binary file 입출력
- text 파일을 제외한 나머지.
- 모드 : 목적+데이터형식(b) => rb, wb
- 메소드 : write(), read() # readline(s)는 txt용이라 안씀.
EX. 이미지 파일 복사하는 코드
=> 두 단계로 진행된다. (1. 읽고 -> 2.쓰기(다른파일명))
1. 파일 Read
# EX. img.jpg 을 복사
# 1. 파일 읽기
try:
fi = open('img.jfif', 'rb')
img = fi.read()
print(type(img)) # 확인 byte 타입
finally:
fi.close()
2. 파일 Write : 다시쓰기-다른파일명
# EX. img.jpg 을 복사
# 2. 파일 쓰기
try:
fo = open('img3.jfif', "wb")
fo.write(img)
finally:
fo.close
EX. 이미지 파일 복사하는 코드 _ 두 단계를 한 번에 하고 싶을 때 _ 중복 with 문
# img.jpg 을 복사 (읽은 뒤에 다시쓰기-다른파일명)
# 1.2. 단계 한번에 하고 싶을 때 with문 두 개로
with open('img.jfif','rb') as fi: # Read 객체 fi
with open('img3.jfif', 'wb') as fo: # Write 객체 fo
img = fi.read() # img파일을 읽어와서 img 변수에 저장하고
fo.write(img) # img변수를 통해 img3 파일에 저장한다.
- 이렇게 read 객체 write 객체 각각 불러와 함께 처리하고 다 하면 with로 파일 닫기
6. pickle
- 파이썬 객체(모든 종류의 값)을 binary로 입출력할 때 사용하는 모듈.
- 입출력을 위해 모든 데이터를 변환!!해주는 모듈
- import pickle : 사용을 위해 피클 모듈을 import 해줘야 한다.
(1) write
pickle.dump(data, fo) #쓰기. 저장.
EX. 리스트 객체를 파일에 저장하기 (write)
# 리스트 객체를 파일에 저장
import pickle # 피클 모듈을 import
data = ['abc', '가나다', True, 1000, 200, 30.67]
with open('list.pkl', 'wb') as fo:
pickle.dump(data, fo) #쓰기. 저장.
type(data) # 원본데이터를 바꾸는 것은 아니고 입출력할 때 binary로 변환하는 것.
(2) read
read_list = pickle.load(fi)
- 이렇게 피클로 정한 파일도 원래 데이터 타입 list로 읽을 수 있다.
# 피클로 정한 데이터(리스트)를 읽기
with open('list.pkl','rb') as fi:
read_list = pickle.load(fi)
read_list
EX. 위 예제 클래스 객체 함수로 구현하기
# 클래스 선언
class item:
def __init__(self, name, price):
self.name, self.price = name, price
def __str__(self):
return f"Type: {type(self)}, name: {self.name}, price:{self.price}"
# 리스트 객체를 파일에 저장 쓰기
import pickle # 피클 모듈을 import
data = item('tv', 250000)
with open('list.pkl', 'wb') as fo:
pickle.dump(data, fo) #쓰기. 저장.
# 2 피클로 정한 데이터(리스트)를 읽기
with open('list.pkl','rb') as fi:
read_list = pickle.load(fi)
print(read_list)
print(type(read_list))
## CSV (Comma Separated Value) 파일 형식
- 데이터를 표형태로 텍스트파일에 저장하기 위한 문서형식
- 하나의 데이터는 한 줄에 작성 (엔터 : 데이터값 구분자)
- 하나의 데이터를 구성하는 속성값들은 ',' 로 구분
[TODO 문제 1 _ 간단한 메모장]
사용자로부터 파일명을 입력받는다.(input())
사용자로 부터 파일에 저장할 문장을 입력받아서 파일에 저장한다. ->반복
사용자가 !q 를 입력하면 종료한다. -> 조건
사용자가 저장한 파일을 읽어서 출력한다.
- 코드 -
def simple_memo():
fname = input("파일명은?:")
with open(fname, "wt") as fw:
print("내용을 입력하시오.")
print("----------")
while True:
line =input()
if line == "qi":
break
else:
fw.write(line+"\n")
with open(fname, "rt") as fi:
r1 = fi.read()
print("------------")
print("<입력받은 값>")
print(r1)
simple_memo()
[TODO 문제 2.1 _ csv 파일을 읽어서 각 열의 값을 배열에 담는다.]
이름,나이,주소 형태의 csv를 읽어
names = []
ages =[]
address =[]
리스트에 넣는다. (라인이 index가 된다.)
파일 member.csv
name,age,address
김영수,20,서울
박영희,21,서울
오민수,30,부산
최정길,15,인천
이명수,22,광주
이철수,17,대전
- 코드 -
# 풀이 코드
names = []
ages = []
address = []
with open("member.csv", "rt", encoding="utf-8") as fi:
for idx, line_num in enumerate(fi):
if idx == 0: # 첫번째 줄 제외를 위해
continue
info = line_num.split(",") # 구분자로 나눠주기
names.append(info[0])
ages.append(info[1])
address.append(info[2].strip()) # \n을 없앨 수 있다.
fi.close
print(names)
print(ages)
print(address)
['김영수', '박영희', '오민수', '최정길', '이명수', '이철수']
['20', '21', '30', '15', '22', '17']
['서울', '서울', '부산', '인천', '광주', '대전']
# 내가 푼 것
names =[]
ages =[]
address=[]
with open("member.csv", "rt", encoding="utf-8") as fi:
text_list = fi.readlines()
for line_num in text_list[1:]:
info = line_num.split(",")
names.append(info[0])
ages.append(info[1])
address.append(info[2].strip())
fi.close
print(names)
print(ages)
print(address)
- info[2].strip() : # \n을 없앨 수 있다.
[TODO 문제 2.2 _ name, ages, address => member_ 2.csv 파일에 csv 형식으로 저장하기(zip()) .]
# EX. name, ages, address => member_ 2.csv 파일에 csv 형식으로 저장하기(zip())
with open("member_2.csv","wt", encoding="utf-8") as fi:
fi.write("name,age,address\n")
#같은 인덱스끼리 튜플로 묶어서 # 튜플대입
for name, age, addr in zip(names,ages,address):
fi.write(f"{name},{age},{addr}\n")
fi.closed
- 튜플 그대로 str 변환해 쓰기하면 괄호()까지 파일에 저장됨. => 튜플대입해주기
'AI_STUDY > Python' 카테고리의 다른 글
Python _DB : pymysql 을 이용해 mysql 연동 (0) | 2022.06.04 |
---|---|
아나콘다 가상환경 생성 및 활성화 (Python, Windows) & 패키지 pip 설치 (pandas jupyter matplotlib) (0) | 2022.06.03 |
python 프로그래밍 : 정규표현식 (0) | 2022.05.23 |
python 프로그래밍 : 예외와 예외처리 (0) | 2022.05.18 |
python 프로그래밍 : 자료 구조_리스트 (0) | 2022.05.16 |