refactor(io): 移除分块读取功能并简化矢量数据读取逻辑
移除 read_vector 函数中的 chunk_size 参数及相关分块读取逻辑,简化代码结构 保留 rows 参数用于数据预览功能,并更新相关文档说明
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -25,6 +25,7 @@ env/
|
|||||||
# ── IDE ─────────────────────────────────────────────────────────────────────
|
# ── IDE ─────────────────────────────────────────────────────────────────────
|
||||||
.idea/
|
.idea/
|
||||||
.vscode/
|
.vscode/
|
||||||
|
.trae/
|
||||||
*.swp
|
*.swp
|
||||||
*.swo
|
*.swo
|
||||||
.DS_Store
|
.DS_Store
|
||||||
@@ -37,6 +38,7 @@ output/*
|
|||||||
!output/.gitkeep
|
!output/.gitkeep
|
||||||
|
|
||||||
# ── GIS 真实数据(保留示例数据,忽略用户数据)────────────────────────────────
|
# ── GIS 真实数据(保留示例数据,忽略用户数据)────────────────────────────────
|
||||||
|
wiki/
|
||||||
data/*
|
data/*
|
||||||
!data/sample/
|
!data/sample/
|
||||||
!data/sample/**
|
!data/sample/**
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
# 给 AI 助手看的规则 - 小白专用版
|
|
||||||
|
|
||||||
## 关于内存(最重要)
|
|
||||||
1. 凡是读文件的函数,只要没加 `rows` 限制或 `chunk_size` 分块,都要在注释里用【警告】两个字提醒用户注意内存风险。
|
|
||||||
2. 不要用 `for` 循环一行行修改 GeoDataFrame,要用 `apply` 或者向量化操作。
|
|
||||||
|
|
||||||
## 关于报错
|
|
||||||
3. 禁止直接把底层库(fiona, shapely)的英文报错抛给用户看。必须包一层 try-except,翻译成中文提示,例如:“文件打不开,检查一下路径是不是有中文?”或者“数据里有烂掉的图形,已自动修复/跳过”。
|
|
||||||
@@ -35,7 +35,6 @@ def read_vector(
|
|||||||
layer: str | int | None = None,
|
layer: str | int | None = None,
|
||||||
crs: str | int | None = None,
|
crs: str | int | None = None,
|
||||||
encoding: str = "utf-8",
|
encoding: str = "utf-8",
|
||||||
chunk_size: int | None = None,
|
|
||||||
rows: int | None = None,
|
rows: int | None = None,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
):
|
):
|
||||||
@@ -51,9 +50,6 @@ def read_vector(
|
|||||||
读取后强制重投影到目标 CRS(不传则保留原始 CRS)。
|
读取后强制重投影到目标 CRS(不传则保留原始 CRS)。
|
||||||
encoding:
|
encoding:
|
||||||
属性表编码,Shapefile 中文路径常需指定 ``"gbk"``。
|
属性表编码,Shapefile 中文路径常需指定 ``"gbk"``。
|
||||||
chunk_size:
|
|
||||||
分块大小,默认 None(一次性读取全部数据)。
|
|
||||||
【警告】:若不设置 chunk_size,大文件可能会占用大量内存。
|
|
||||||
rows:
|
rows:
|
||||||
限制读取的行数,默认 None(读取全部数据)。
|
限制读取的行数,默认 None(读取全部数据)。
|
||||||
用于快速预览数据,避免读取大文件的全部内容。
|
用于快速预览数据,避免读取大文件的全部内容。
|
||||||
@@ -62,22 +58,15 @@ def read_vector(
|
|||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
gpd.GeoDataFrame 或生成器
|
gpd.GeoDataFrame
|
||||||
如果 chunk_size 为 None,返回完整的 GeoDataFrame;
|
读取的矢量数据。
|
||||||
如果设置了 chunk_size,返回一个生成器,每次 yield 一个 GeoDataFrame 块。
|
|
||||||
|
|
||||||
示例
|
示例
|
||||||
-----
|
-----
|
||||||
# 全量读取(老方法)
|
### 全量读取
|
||||||
gdf = read_vector("data.shp")
|
gdf = read_vector("data.shp")
|
||||||
|
|
||||||
# 分块读取(新方法)
|
### 只读取前 5 行数据(预览模式)
|
||||||
for chunk in read_vector("large_data.shp", chunk_size=10000):
|
|
||||||
# 处理每个数据块
|
|
||||||
print(f"处理了 {len(chunk)} 条数据")
|
|
||||||
# 在这里做你的操作,比如计算、过滤等
|
|
||||||
|
|
||||||
# 只读取前 5 行数据(预览模式)
|
|
||||||
gdf_preview = read_vector("large_data.shp", rows=5)
|
gdf_preview = read_vector("large_data.shp", rows=5)
|
||||||
print(gdf_preview.head())
|
print(gdf_preview.head())
|
||||||
"""
|
"""
|
||||||
@@ -88,56 +77,13 @@ def read_vector(
|
|||||||
logger.info("读取矢量数据:%s(格式:%s,图层:%s)", path, suffix or "目录", layer)
|
logger.info("读取矢量数据:%s(格式:%s,图层:%s)", path, suffix or "目录", layer)
|
||||||
|
|
||||||
if suffix == ".csv":
|
if suffix == ".csv":
|
||||||
# CSV 文件暂时不支持分块读取
|
|
||||||
if chunk_size is not None:
|
|
||||||
logger.warning("CSV 文件暂不支持分块读取,将一次性读取全部数据")
|
|
||||||
return _read_csv_vector(path, crs=crs, **kwargs)
|
return _read_csv_vector(path, crs=crs, **kwargs)
|
||||||
|
|
||||||
# fiona / geopandas 通用读取
|
|
||||||
read_kwargs: dict[str, Any] = {"encoding": encoding, **kwargs}
|
read_kwargs: dict[str, Any] = {"encoding": encoding, **kwargs}
|
||||||
if layer is not None:
|
if layer is not None:
|
||||||
read_kwargs["layer"] = layer
|
read_kwargs["layer"] = layer
|
||||||
|
|
||||||
# 分块读取模式
|
|
||||||
if chunk_size is not None:
|
|
||||||
def _chunk_generator():
|
|
||||||
logger.info("启用分块读取模式,每块 %d 条数据", chunk_size)
|
|
||||||
try:
|
try:
|
||||||
# 使用 fiona 打开文件
|
|
||||||
with fiona.open(str(path), **read_kwargs) as src:
|
|
||||||
# 获取坐标系信息
|
|
||||||
crs_info = src.crs
|
|
||||||
# 分块读取
|
|
||||||
features = []
|
|
||||||
for i, feature in enumerate(src):
|
|
||||||
# 检查是否达到行数限制
|
|
||||||
if rows is not None and i >= rows:
|
|
||||||
break
|
|
||||||
|
|
||||||
features.append(feature)
|
|
||||||
if (i + 1) % chunk_size == 0:
|
|
||||||
# 创建 GeoDataFrame 并设置 CRS
|
|
||||||
gdf = gpd.GeoDataFrame.from_features(features, crs=crs_info)
|
|
||||||
# 重投影
|
|
||||||
if crs is not None:
|
|
||||||
gdf = gdf.to_crs(crs) # type: ignore
|
|
||||||
logger.debug("读取并处理第 %d 块数据,共 %d 条", (i + 1) // chunk_size, len(gdf))
|
|
||||||
yield gdf
|
|
||||||
features = []
|
|
||||||
# 处理最后一块
|
|
||||||
if features:
|
|
||||||
gdf = gpd.GeoDataFrame.from_features(features, crs=crs_info)
|
|
||||||
if crs is not None:
|
|
||||||
gdf = gdf.to_crs(crs) # type: ignore
|
|
||||||
logger.debug("读取并处理最后一块数据,共 %d 条", len(gdf))
|
|
||||||
yield gdf
|
|
||||||
except Exception as exc:
|
|
||||||
raise RuntimeError(f"无法分块读取矢量数据:{exc}") from None
|
|
||||||
return _chunk_generator()
|
|
||||||
else:
|
|
||||||
# 一次性读取模式
|
|
||||||
try:
|
|
||||||
# 添加 rows 参数到读取参数中
|
|
||||||
if rows is not None:
|
if rows is not None:
|
||||||
read_kwargs["rows"] = rows
|
read_kwargs["rows"] = rows
|
||||||
logger.info("限制读取行数:%d", rows)
|
logger.info("限制读取行数:%d", rows)
|
||||||
@@ -151,7 +97,7 @@ def read_vector(
|
|||||||
gdf = gdf.to_crs(crs) # type: ignore
|
gdf = gdf.to_crs(crs) # type: ignore
|
||||||
|
|
||||||
logger.info("读取完成:共 %d 条要素,CRS=%s", len(gdf), gdf.crs)
|
logger.info("读取完成:共 %d 条要素,CRS=%s", len(gdf), gdf.crs)
|
||||||
return gdf # type: ignore
|
return gdf
|
||||||
|
|
||||||
|
|
||||||
# ── GDB 专用 ───────────────────────────────────────────────────────────────────
|
# ── GDB 专用 ───────────────────────────────────────────────────────────────────
|
||||||
|
|||||||
13
tests/test.py
Normal file
13
tests/test.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# 将项目根目录添加到系统路径中,以便导入模块
|
||||||
|
sys.path.append(str(Path(__file__).parent.parent))
|
||||||
|
from app.io.readers import read_vector
|
||||||
|
# 读取 GeoJSON 文件
|
||||||
|
data_path = Path(r"D:\工作\三普成果编制\出图数据\永德\制表\制表数据.gdb\AK")
|
||||||
|
|
||||||
|
# 或者使用 rows 参数直接只读取前5行
|
||||||
|
print("\n使用 rows 参数预览:")
|
||||||
|
gdf_preview = read_vector(data_path, rows=5)
|
||||||
|
print(gdf_preview)
|
||||||
Reference in New Issue
Block a user