Ostatnio aktywny 1773041484

Rewizja 9410e55e320b5690f10cc0fda0608eb3d4deb4ae

2025임상도갱신.py Surowy
1import os
2import subprocess
3from datetime import datetime
4import sys
5
6PGHOST = "127.0.0.1"
7PGPORT = 5433
8PGDB = "postgres"
9PGUSER = "postgres"
10PGPASS = "postgres123"
11PGSCHEMA = "public"
12PGTABLE = "foresttype_2025"
13
14S_SRS = "EPSG:5179"
15T_SRS = "EPSG:5186"
16
17GDB_PATH = r"C:\Users\ASUS\Desktop\dadrim\T2025imsangdo.gdb"
18
19# GDB내에 존재하는 레이어명 명시
20SOURCE_LAYERS = [
21 "T2025_일반임상도",
22 "T2025_접경임상도",
23]
24
25TRUNCATE_BEFORE_LOAD = False
26
27LOG_DIR = os.path.dirname(GDB_PATH)
28LOGFILE = os.path.join(LOG_DIR, f"import_log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt")
29
30
31def logger(message: str):
32 ts = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
33 line = f"[{ts}] {message}"
34 with open(LOGFILE, "a", encoding="utf-8") as f:
35 f.write(line + "\n")
36 print(line)
37
38
39def run_cmd(cmd, env=None, timeout=None):
40 try:
41 res = subprocess.run(
42 cmd,
43 env=env,
44 capture_output=True,
45 text=True,
46 encoding="utf-8",
47 errors="replace",
48 timeout=timeout
49 )
50 return res.returncode, res.stdout, res.stderr
51 except subprocess.TimeoutExpired as e:
52 return 999, e.stdout or "", f"TIMEOUT after {timeout}s"
53
54
55def psql_cmd(sql: str, timeout=60):
56 env = os.environ.copy()
57 env["PGPASSWORD"] = PGPASS
58 return run_cmd(
59 ["psql", "-h", PGHOST, "-p", str(PGPORT), "-U", PGUSER, "-d", PGDB, "-v", "ON_ERROR_STOP=1", "-c", sql],
60 env=env,
61 timeout=timeout
62 )
63
64
65def check_connection() -> bool:
66 code, out, err = psql_cmd("SELECT 'DB_CONNECTED';", timeout=10)
67 if code == 0 and "DB_CONNECTED" in out:
68 logger(">> DB 접속 확인 성공!")
69 return True
70 logger(f">> DB 접속 실패: {err.strip() or out.strip()}")
71 return False
72
73
74def table_exists(schema: str, table: str) -> bool:
75 sql = (
76 "SELECT EXISTS ("
77 " SELECT 1 FROM information_schema.tables"
78 f" WHERE table_schema = '{schema}' AND table_name = '{table}'"
79 ");"
80 )
81 env = os.environ.copy()
82 env["PGPASSWORD"] = PGPASS
83
84 code, out, err = run_cmd(
85 ["psql", "-h", PGHOST, "-p", str(PGPORT), "-U", PGUSER, "-d", PGDB, "-t", "-A", "-c", sql],
86 env=env,
87 timeout=30
88 )
89 if code != 0:
90 raise RuntimeError(err.strip() or out.strip())
91
92 return out.strip().lower() == "t"
93
94
95def truncate_target_table():
96 sql = f'TRUNCATE TABLE "{PGSCHEMA}"."{PGTABLE}";'
97 code, out, err = psql_cmd(sql, timeout=60)
98 if code != 0:
99 raise RuntimeError(err.strip() or out.strip())
100 logger(f'대상 테이블 TRUNCATE 완료: {PGSCHEMA}.{PGTABLE}')
101
102
103def run_ogr2ogr_layer(layer_name: str):
104 conn_str = f"PG:host={PGHOST} port={PGPORT} dbname={PGDB} user={PGUSER} password={PGPASS}"
105
106 cmd = [
107 "ogr2ogr",
108 "-f", "PostgreSQL",
109 conn_str,
110 GDB_PATH,
111 layer_name,
112 "-nln", f"{PGSCHEMA}.{PGTABLE}",
113 "-append",
114 "-nlt", "PROMOTE_TO_MULTI",
115 "-s_srs", S_SRS,
116 "-t_srs", T_SRS,
117 "--config", "PG_USE_COPY", "YES",
118 "-gt", "10000",
119 "-progress"
120 ]
121
122 logger(f"ogr2ogr 실행 레이어명: {layer_name}")
123
124 code, out, err = run_cmd(cmd, timeout=60 * 60 * 6)
125 if code != 0:
126 return False, (err.strip() or out.strip())
127 return True, ""
128
129
130def create_index_and_analyze():
131 sql = (
132 f'CREATE INDEX IF NOT EXISTS "{PGTABLE}_geom_idx" '
133 f'ON "{PGSCHEMA}"."{PGTABLE}" USING GIST (geom); '
134 f'ANALYZE "{PGSCHEMA}"."{PGTABLE}";'
135 )
136 code, out, err = psql_cmd(sql, timeout=60 * 60)
137 if code != 0:
138 raise RuntimeError(err.strip() or out.strip())
139
140
141def main():
142 if not check_connection():
143 logger("DB 접속 실패로 프로그램을 종료합니다.")
144 sys.exit(1)
145
146 exists = table_exists(PGSCHEMA, PGTABLE)
147 logger(f'대상 테이블 존재 여부: {"EXISTS" if exists else "NOT EXISTS"} ({PGSCHEMA}.{PGTABLE})')
148 if not exists:
149 logger("대상 테이블이 없습니다. Postgres에 테이블을 미리 생성한 뒤 다시 실행하세요.")
150 sys.exit(1)
151
152
153 if TRUNCATE_BEFORE_LOAD:
154 try:
155 truncate_target_table()
156 except Exception as e:
157 logger(f"TRUNCATE 실패: {e}")
158 sys.exit(1)
159
160 total_start = datetime.now()
161 error_layers = []
162
163 for i, layer in enumerate(SOURCE_LAYERS, start=1):
164 logger(f"[{i}/{len(SOURCE_LAYERS)}] 레이어 적재 시작: {layer}")
165 start = datetime.now()
166
167 ok, msg = run_ogr2ogr_layer(layer)
168 sec = (datetime.now() - start).total_seconds()
169
170 if ok:
171 logger(f"[{i}/{len(SOURCE_LAYERS)}] 적재 완료: {layer} ({sec:.2f}s)")
172 else:
173 logger(f"[{i}/{len(SOURCE_LAYERS)}] 적재 실패: {layer} ({sec:.2f}s) / 사유: {msg}")
174 error_layers.append(layer)
175
176 logger("GIST 인덱스 생성 및 ANALYZE 시작")
177 try:
178 create_index_and_analyze()
179 logger("GIST 인덱스 생성 및 ANALYZE 완료")
180 except Exception as e:
181 logger(f"인덱스 생성/ANALYZE 실패(수동 확인 필요): {e}")
182
183 total_sec = (datetime.now() - total_start).total_seconds()
184 logger("=" * 60)
185 logger("전체 종료")
186 logger(f"총 소요시간: {total_sec:.2f}초 ({total_sec/60:.1f}분)")
187 logger(f"로그: {LOGFILE}")
188 logger("=" * 60)
189
190 if error_layers:
191 print("\n!! 실패한 레이어 목록:", error_layers)
192
193
194if __name__ == "__main__":
195 main()
foresttype_2025.sql Surowy
1CREATE SEQUENCE public.foresttype_2025_gid_seq;
2
3CREATE TABLE public.foresttype_2025 (
4 gid int4 DEFAULT nextval('foresttype_2025_gid_seq'::regclass) NOT NULL,
5 objectid int8 NULL,
6 storunst varchar(254) NULL,
7 fror_cd varchar(254) NULL,
8 frtp_cd varchar(254) NULL,
9 koftr_grou varchar(254) NULL,
10 dmcls_cd varchar(254) NULL,
11 agcls_cd varchar(254) NULL,
12 dnst_cd varchar(254) NULL,
13 height varchar(2) NULL,
14 ldmark_stn varchar(254) NULL,
15 map_label varchar(10) NULL,
16 varchar(8) NULL,
17 etc_pcmtt varchar(100) NULL,
18 frtp_nm varchar(100) NULL,
19 koftr_nm varchar(100) NULL,
20 dmcls_nm varchar(100) NULL,
21 agcls_nm varchar(100) NULL,
22 dnst_nm varchar(100) NULL,
23 shape_length float8 NULL,
24 shape_area float8 NULL,
25 geom public.geometry(multipolygon, 5186) NULL,
26 CONSTRAINT foresttype_2025_pkey PRIMARY KEY (gid)
27);