본문 바로가기

python

python - 외부 파일 처리/ Excel , CSV 파일 읽기 및 쓰기

파이썬 외부 파일 처리 방법 + 전 시간에는 파이썬 파일 읽기 쓰기 추가 배웠고

이번엔 Excel , CSV 파일 읽기 및 쓰기 배운다.

 

CSV - MIME 타입 = text/csv 이다.  Multipurpose Internet Mail Extensions

MIME 타입이란? 클러이언트에게 전송된 문서의 다양성을 알려주기 위한 메커니즘이다.  파일 변환을 뜻한다고할 수 있습니다.  이메일과 함께 동봉할 파일을 텍스트 문자로 전환해서 이메일 시스템을 통해 전달하기 위해 개발
MIME 형식

 

파일 이름 확장명 : .gif

 

MIME 형식 : image/gif

[파일의 종류 / 파일포맷]

 

MIME 형식을 보면 앞부분의 파일의 종류(image) / 파일포맷(gif) 형태로 정의 된다.

 

* MIME 형식에는 공백, 대/소문자를 구분하지 않으며 대부분 소문자로 쓰인다.

CSV(영어: comma-separated values)는 몇 가지 필드를 쉼표(,)로 구분한 텍스트 데이터 및 텍스트 파일이다. 확장자는 .csv이며 MIME 형식은 text/csv이다. comma-separated variables라고도 한다.

import csv # 모듈 임포트(내포) 하기

with open('./resource/sample.csv','r') as f :
	reader = csv.reader(f) 
    # next(reader) Header 스킵
    
    print(reader)
    print(type(reader))
    print(dir(reader))
    print()
    
    for c in reader :
    	print(c)

 

우선 csv 파이썬 내장 모듈을 임포트(내포) 해준 뒤 csv 모듈 안에 있는 csv.reader() 함수를 이용해 파일 읽기가 할당된 변수를 파라미터로 넣고 reader 라는 변수에 인스턴스를 할당(파이썬은 함수도 객체이므로)하고 reader 변수를 프린터 해주면, 타입은 _csv.reader 클래스 이고, dir 안에 __iter__ 메소드가 있기 때문에 반복문 사용이 가능하다.

반복문을 사용해서 reader 안의 csv 파일의 데이터를 한줄씩 list 형태로 읽어오면 다음과 같은 결과가 나온다.

결과값

더보기

1. Iterator

리스트, Set, Dictionary와 같은 컬렉션이나 문자열과 같은 문자 Sequence 등은 for 문을 써서 하나씩 데이타를 처리할 수 있는데, 이렇게 하나 하나 처리할 수 있는 컬렉션이나 Sequence 들을 Iterable 객체(Iterable Object)라 부른다.

1

2

3

4

5

6

7

# 리스트 Iterable

for n in [1,2,3,4,5]:

    print(n)

 

# 문자열 Iterable

for c in "Hello World":

    print(c)

 

내장 함수 iter()는 "iter(Iterable객체)" 와 같이 사용하여 그 Iterable 객체의 iterator를 리턴한다. Iterable 객체에서 실제 Iteration을 실행하는 것은 iterator로서, iterator는 next 메서드를 사용하여 다음 요소(element)를 가져온다. 만약 더이상 next 요소가 없으면 StopIteration Exception을 발생시킨다.

Iterator의 next 메서드로서 Python 2에서는 "iterator객체.next()" 를 사용하고, Python 3에서는 "iterator객체.__next__()" 메서드를 사용한다. 또한, 버전에 관계없이 사용할 수 있는 방식으로 내장 함수 "next(iterator객체)" 를 사용할 수 있다. 아래는 한 리스트에 대해 list iterator를 구한 후, next() 함수를 계속 호출해 본 예이다.

어떤 클래스를 Iterable 하게 하려면, 그 클래스의 iterator를 리턴하는 __iter__() 메서드를 작성해야 한다. 이 __iter__() 메서드가 리턴하는 iterator는 동일한 클래스 객체가 될 수도 있고, 별도로 작성된 iterator 클래스의 객체가 될 수도 있다. 어떠한 경우든 Iterator가 되는 클래스는 __next()__ 메서드 (Python 2 인 경우 next() 메서드) 를 구현해야 한다. 실제 for 루프에 Iterable Object를 사용하면, 해당 Iterable의 __iter__() 메서드를 호출하여 iterator를 가져온 후 그 iterator의 next() 메서드를 호출하여 루프를 돌게 된다.

아래 예제는 간단한 Iterator를 예시한 것으로 __iter__() 메서드에서 self 를 리턴함으로써 Iterable과 동일한 클래스에 Iterator를 구현했음을 표시하였고, 그 클래스 안에 Iterator로서 필요한 __next__() 메서드 (Python 3)를 구현하였다.

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

class MyCollection:

    def __init__(self):

        self.size = 10

        self.data = list(range(self.size))

 

    def __iter__(self):

        self.index = 0

        return self

 

    def __next__(self):

        if self.index >= self.size:

            raise StopIteration

 

        n = self.data[self.index]

        self.index += 1

        return n

 

 

coll = MyCollection()

for x in coll:

    print(x)

2. Generator

Generator는 Iterator의 특수한 한 형태이다.
Generator 함수(Generator function)는 함수 안에 yield 를 사용하여 데이타를 하나씩 리턴하는 함수이다. Generator 함수가 처음 호출되면, 그 함수 실행 중 처음으로 만나는 yield 에서 값을 리턴한다. Generator 함수가 다시 호출되면, 직전에 실행되었던 yield 문 다음부터 다음 yield 문을 만날 때까지 문장들을 실행하게 된다. 이러한 Generator 함수를 변수에 할당하면 그 변수는 generator 클래스 객체가 된다.

아래 예제는 간단한 Generator 함수와 그 호출 사례를 보인 것이다. 여기서 gen() 함수는 Generator 함수로서 3개의 yield 문을 가지고 있다. 따라서 한번 호출시마다 각 yield 문에서 실행을 중지하고 값을 리턴하게 된다.

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

# Generator 함수

def gen():

    yield 1

    yield 2

    yield 3

 

# Generator 객체

g = gen()

print(type(g))  # <class 'generator'>

 

# next() 함수 사용

n = next(g); print(n)  # 1

n = next(g); print(n)  # 2

n = next(g); print(n)  # 3

 

# for 루프 사용 가능

for x in gen():

    print(x)

위의 예에서 g = gen() 문은 Generator 함수를 변수 g 에 할당한 것인데, 이때 g는 generator 라는 클래스의 객체로서 next() 내장함수를 사용하여 Generator의 다음 값을 계속 가져올 수 있다. Generator는 물론 예제의 마지막 부분과 같이 for 루프에서 사용될 수 있다.

리스트나 Set과 같은 컬렉션에 대한 iterator는 해당 컬렉션이 이미 모든 값을 가지고 있는 경우이나, Generator는 모든 데이타를 갖지 않은 상태에서 yield에 의해 하나씩만 데이타를 만들어 가져온다는 차이점이 있다. 이러한 Generator는 데이타가 무제한이어서 모든 데이타를 리턴할 수 없는 경우나, 데이타가 대량이어서 일부씩 처리하는 것이 필요한 경우, 혹은 모든 데이타를 미리 계산하면 속도가 느려서 그때 그때 On Demand로 처리하는 것이 좋은 경우 등에 종종 사용된다.

3. Generator Expression

Generator Expression은 Generator Comprehension으로도 불리우는데, List Comprehension과 외관상 유사하다. List Comprehension은 앞뒤를 [...] 처럼 대괄호로 표현한다면, Generator Expression (...) 처럼 둥근 괄호를 사용한다. 하지만 Generator Expression은 List Comprehension과 달리 실제 리스트 컬렉션 데이타 전체를 리턴하지 않고, 그 표현식만을 갖는 Generator 객체만 리턴한다. 즉 실제 실행은 하지 않고, 표현식만 가지며 위의 yield 방식으로 Lazy Operation을 수행하는 것이다.

아래 예제는 1부터 1000개까지의 숫자에 대한 제곱값을 Generator Expression으로 표현한 것으로 여기서 Generator Expression을 할당받은 변수 g는 Generator 타입 객체이다. 첫번째 for 루프를 사용하여 10개의 next() 문을 실행하여 처음 10개에 대한 제곱값만을 실행하였다. 두번째 for 루프에서는 11번째부터 마지막까지 모두 실행하게 된다. Generator 객체 g는 상태를 유지하고 있으므로 두번째 for 루프에서 다음 숫자 11부터 계산을 수행한 것이다.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

# Generator Expression

g = (n*n for n in range(1001))

 

# g는 generator 객체

print(type(g))  # <class 'generator'>

 

# 리스트로 일괄 변환시

# mylist = list(g)

 

# 10개 출력

for i in range(10):

    value = next(g)

    print(value)

 

# 나머지 모두 출력

for x in g:

    print(x)

with open('./resource/sample2.csv','r') as f :
     reader = csv.reader(f, delimiter= '|') # <- 이값 알아야된다.
    #  next(reader) Header 스킵

     # 확인
     print(reader)
     print(type(reader))
     print(dir(reader))
     print()

     for c in reader:
         print(c)

위와 똑같지만, 아래와 같은 데이터의 경우 csv 형태 즉, comma 가 아닌 " | " 로 구분 되어있기 때문에

위와 똑같이 형태를 list 배열 형태로 가져오고 싶다면, delimiter = ' | ' 를 추가하여  |  <- 이걸로 구분되어 있다는 것을

알려주어 형태에 맞는 데이터를 가져 올 수 있도록 해줄 수 있다.

 

list 형태 를 Dict 형태로 변환해주는 csv.DictReader() 함수 객체를 이용해서 f 파리미터 ( 읽어온 데이터 ) 를 처리 해준다.

이것을 reader에 넣고 Dict( 딕셔너리 ) 형태(__iter__)이므로 바로 for 문을 사용하여 print 해준다.

아래는 실행코드이다.

with open('./resource/sample1.csv','r') as f :
	reader = csv.DictReader(f) # Key : value 형태로 정리해주는 클래스다.
    
    for c in reader :
    	for k,v in c.items() :
        	print(k,v)
        print('--------------')

아래는 csv.DictReader() 클래스에 관한 설명이다.

#The csv module defines the following classes:
class csv.DictReader(f, fieldnames=None, restkey=None, restval=None, dialect='excel', *args, **kwds)
Create an object that operates like a regular reader but maps the information in each row to a dict
whose keys are given by the optional fieldnames parameter.

 

출력은 아래와 같이 된다.

csv.DictReader(f) 출력 결과물

CSV 파일을 쓰기 위해서는 .csv 파일을 쓰기모드로 오픈하고 파일객체를 csv.writer(파일객체) 에 넣으면 된다.

CSV writer는 writerow() 라는 메서드를 통해 list 데이터를 한 라인에 추가하게 된다.

윈도우에서는 csv 모듈에서 데이터 작성시, 각 라인 뒤에 빈 라인이 추가되는 문제가 있는데, 이를 없애기 위해

파일 open 시, newline= " " 로 설정한다.

 

w =[[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13,14,15],[16,17,18]]

with open('./resource/sample3.csv','w', newline='') as f:
    wt = csv.writer(f)

    for v in w:
        wt.writerow(v) # 검증 필요할 떄 if 문 사용시 사용
        
        
 # 혹은 아래처럼 나타낼 수 있다.
 
writer.writerow([1, "김철수", False])
writer.writerow([2, "조현근", True])

쓰기 모드로 오픈하고 파일 객체를 csv.writer()에 넣고 wt에 할당 후 wt(wt 안에 csv.writer 가 있고 그 안에 .writerow() 라는 메서드를 통해 list 데이터를 한 라인 추가하게 된다.

그럼 아래와 같은 값과 파일이 저장되고 생성된다.

아래 코드는 검증이 완료되어 파싱이 필요없이 바로 전부다!! 사용 가능할 때 사용한다.

writerows() 메서드를 사용하면 바로 값 전부를 쓸 수 있다. 즉,

writerow()는 한라인씩 가져오고 writerows()는 전부 가져온다...

with open('./resource/sample4.csv','w', newline='') as f:
    wt = csv.writer(f)
    wt.writerows(w) # 검증 끝나 전부 사용 가능할 때 사용

XSL, XLSX 엑셀 읽어오기

XSL, XLSX

openpyxl, xlsxwriter, xlrd, xlwt, xlutils

pandas 를 주로 사용(openpyxl, xlrd)

설치 : pip install xlrd , openpyxl, pandas

구글에 pandas excel 치면 다 나온다.

 

import pandas as pd

# 옵션 : sheetname='시트명' 또는 숫자, header=숫자, skiprow=숫자
xlsx = pd.read_excel('./resource/sample.xlsx', (옵션))

# 상위 데이터 확인 ( 앞 5행 )
print(xlsx.head()) # 원하는 형태로 파싱(데이터 원하는 형태로 가공)가능
print()

# 데이터 확인 ( 끝부분 뒤 5행 )
print(xlsx.tail())

# 데이터 확인 ( 구조 행(row),열(column) )
print(xlsx.shape)

# 엑셀 or CSV 다시 쓰기
xlsx.to_excel('./resource/result2.xlsx',index=False)
# index=False 0,1,2,3,4 맨앞에 행 쪽 숫자 적어주는거 False (안적겠다)

xlsx 라는 변수에 pandas 모듈의 read_excel("") 메서드를 사용하여 속성값과 엑셀파일 데이터를 가져와 저장하고 xlsx.head()를 사용하면 상위 5행을 보여주고 xlsx.tail() 하면 하위 5행을 파싱해 보여준다.

xlsx.shape는 데이터의 행과 열을 알려준다. 

xlsx.to_excel("파일 만들기", index=False # 앞의 인덱스를 주는것을 안적겠다는 뜻) pandas 안의 메서드를 사용하면

엑셀 파일을 만들어주고, 엑셀 형태로 다시 써서 저장해준다.

to_csv()는 csv 파일을 만들어주고 csv 형태로 다시 써서 저장해준다.