디렉토리 하위 경로를 dict 형태로 파싱하기
최종 목표 : md 문서가 있는 디렉토리 경로를 읽어와 웹페이지에서 마크다운 문서를 랜더하는것.
디렉토리 받아서 하위 경로 DICT + list 형태로 자동 파싱해주는 코드 만들기
def readdir(dir):
tdir = {}
ret = {}
tdir['dir'] = []
for file,key in dir.items() :
if key == None :
tdir['dir'].append(file)
else :
ret = readdir(key)
ret['fname'] = file
tdir['dir'].append(ret)
return tdir
def dirparser(rootdir):
dir = {}
res = os.walk(rootdir)
rootdir = rootdir.rstrip(os.sep)
start = rootdir.rfind(os.sep) + 1
for path, dirs, files in res:
folders = path[start:].split(os.sep)
subdir = dict.fromkeys(files)
parent = reduce(dict.get, folders[:-1], dir)
# print(type(subdir))
parent[folders[-1]] = subdir
return readdir(dir)
rdir = "dir"
print(dirparser(rdir))
{
'dir': [
{'dir':
['doctest1.md', 'doctest1_copy.md',
{'dir': ['서포트+로그+타입 copy.md', '서포트+로그+타입.md'], 'fname': 'folder1'},
{'dir': ['서포트+로그+타입 copy.md', '서포트+로그+타입.md'], 'fname': 'folder13'},
{'dir': ['doctest1_copy_2.md',
{'dir': [
'doctest1_copy_3.md',
{'dir': [], 'fname': 'f1'},
{'dir': [], 'fname': 'f2'}
],
'fname': 'folder2_1'}
],
'fname': 'folder2'}
],
'fname': 'docs'}
]
}
None이 아닌 경우 -> dir.items() 에 의해 k1,k2로 구분되어 반복문 돌아감
k2가 None인 경우 -> k1을 출력
아닌 경우 -> dir.items()에 의해 ~
None인 경우-> 이름을 출력
파싱 된다. 이제 해야하는것
None인 경우 - 'name' : 'fname + 들어갈때도 파일이름 저장은 공통적으로 필요함.
아닌 경우 - dir : 'dict' 형식으로 세팅 필요함.
딕셔너리 반환하는 식으로 인자 체크 가능?
[
name : file
dir : [
{
name : file
dir : {}
},
]
]
저 name과 dir가 들어있는 딕셔너리가 통째로 반환되어야함.
맨 마지막의 dir은 (None을 만나는 경우) -> 파일 이름만 반환되고 dir는 비어있을(None이 될) 예정.
그리고 어쨋든 None이 아니면 현재 디렉토리 구조가 있다는 이야기 -> 폴더 이름을 만들어야한다.
== None인 경우 파일이라는 뜻.
현재 디렉토리 탐색이 끝났는데 dir이 비어있는경우
-> 더 내려갈 하위 디렉토리가 없음. 현재 디렉토리 이름이 현재 dict의 fname 요소가 되어야함.
반환받은 요소를 검사할 필요가 있나? -> 반환받은 dir 요소의 dict가 비어있는 경우, 해당 dir요소는 최 하위 디렉토리라는 의미가 되므로, 가지고 있는 이름을 fname으로 지정해줘야 한다. -> 아님.
그냥 요소를 반환받을때 반환받은 dict에 fame 추가해주면됨.;; 간단하게 생각하자
jinja에서의 결과물 출력 방식
'fname' : 'foldername' ,
'dir' : [ 'filename',
{'dir' : [] , 'fname' : 'f1' },
{'dir' : [] , 'fname' : 'f2' },
]
- 폴더이름은 디렉토리당 한번씩만 출력됨
- dir 내부 요소에 폴더랑 파일이 모두 포함됨.
- 요소 타입이 string일 경우 파일명 → 그냥 출력하면됨
- string이 아닌경우 디렉토리 → 반복문 진행
- fname이 없는 경우 → 이 경우도 그냥 출력
{% for d1 in dir['dir'] %}
name1 : {{ d1['fname'] }} <br>
{% for d2 in d1['dir'] %}
{% if d2['fname'] %}
name2 : {{ d2['fname'] }} <br>
{% else %}
file2 : {{ d2 }} <br>
{% endif %}
{% for d3 in d2['dir'] %}
{% if d3['fname'] %}
name3 : {{ d3['fname'] }} <br>
{% else %}
file3 : {{ d3 }} <br>
{% endif %}
{% for d4 in d3['dir'] %}
{% if d4['fname'] %}
name4 : {{ d4['fname'] }} <br>
{% else %}
file4 : {{ d4 }} <br>
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
파일을 불러오기 위해서는 디렉토리 경로도 표기해줘야한다.
이건 파싱함수 코드를 좀 바꿔야할듯. 디렉토리를 내려갈 때 마다 상위 디렉토리 이름을 누적 표기하는 식으로 해보자.
{% for d1 in dir['dir'] %}
name1 : {{ d1['fname'] }} <br>
{% for d2 in d1['dir'] %}
{% set dname1 = d1['fname']+"/" %}
{% if d2['fname'] %}
name2 : {{ dname1+d2['fname'] }} <br>
{% else %}
file2 : {{ dname1+d2 }} <br>
{% endif %}
{% for d3 in d2['dir'] %}
{% set dname2 = dname1+d2['fname']+"/" %}
{% if d3['fname'] %}
name3 : {{ dname2+d3['fname'] }} <br>
{% else %}
file3 : {{ dname2+d3 }} <br>
{% endif %}
{% for d4 in d3['dir'] %}
{% set dname3 = dname2+d3['fname']+"/" %}
{% if d4['fname'] %}
name4 : {{ dname3+d4['fname'] }} <br>
{% else %}
file4 : {{ dname3+d4 }} <br>
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
혹은 경우에 따라 파일에만 전체 디렉토리가 나오게 할수도 있다.
{% for d1 in dir['dir'] %}
name1 : {{ d1['fname'] }} <br>
{% for d2 in d1['dir'] %}
{% set dname1 = d1['fname']+"/" %}
{% if d2['fname'] %}
name2 : {{ d2['fname'] }} <br>
{% else %}
file2 : {{ dname1+d2 }} <br>
{% endif %}
{% for d3 in d2['dir'] %}
{% set dname2 = dname1+d2['fname']+"/" %}
{% if d3['fname'] %}
name3 : {{ d3['fname'] }} <br>
{% else %}
file3 : {{ dname2+d3 }} <br>
{% endif %}
{% for d4 in d3['dir'] %}
{% set dname3 = dname2+d3['fname']+"/" %}
{% if d4['fname'] %}
name4 : {{ d4['fname'] }} <br>
{% else %}
file4 : {{ dname3+d4 }} <br>
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
flaks에서 markdown 문서 출력하기
pip install Flask-markdown
flask-markdown 패키지 설치
이후 init 파일에 flask app 추가
app = Flask(__name__,static_url_path='/static')
~~~~
Markdown(app,extensions=['nl2br','fenced_code'])
app 추가되었으면 view 문서에서 아래와 같이 작성
mf = open(rootpath+'\\'+fname,"r",encoding='UTF8')
md = mf.read()
#md = "## Your Markdown Here "
return render_template('docbase.html',dir=r,doc=fname,md=md)
랜더할때 그냥 인자로 읽어들인 마크다운 텍스트 내용을 그대로 넘겨주면 된다.
<div class="container-fluid" style="margin-left:25%">
<div>
<h6>file path : {{ doc }}</h6>
{% if md %}
<div>{{ md|markdown }}</div>
{% else %}
{% endif %}
</div>
</div>
html 템플릿 파일은 받아온 내용을 그대로 markdown 형태로 출력하면 됨.
### MD TEST DOC
1. 마크다운 테스트 문서입니다
2. 마크다운 텍스트?
- 마크당우우우우운
- 마아아읔 다운
markdown code highlights test
그러면 저렇게 나온다.
파일 오픈시 'cp949' 인코딩 에러
"UnicodeDecodeError: 'cp949' codec can't decode byte 0xe2 in position 6987: illegal multibyte sequence"
파일 입출력시 위와같은 에러가 날떄가 있는데, 파일을 읽을때 인코딩이 잘못되어 발생하는 에러다.
mf = open(rootpath+'\\'+fname,"r",**encoding='UTF8'**)
encoding='UTF8' 로 인코딩 명시해주면 해결