refactor(io): 移除分块读取功能并简化矢量数据读取逻辑
移除 read_vector 函数中的 chunk_size 参数及相关分块读取逻辑,简化代码结构 保留 rows 参数用于数据预览功能,并更新相关文档说明
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -25,6 +25,7 @@ env/
|
||||
# ── IDE ─────────────────────────────────────────────────────────────────────
|
||||
.idea/
|
||||
.vscode/
|
||||
.trae/
|
||||
*.swp
|
||||
*.swo
|
||||
.DS_Store
|
||||
@@ -37,6 +38,7 @@ output/*
|
||||
!output/.gitkeep
|
||||
|
||||
# ── GIS 真实数据(保留示例数据,忽略用户数据)────────────────────────────────
|
||||
wiki/
|
||||
data/*
|
||||
!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,
|
||||
crs: str | int | None = None,
|
||||
encoding: str = "utf-8",
|
||||
chunk_size: int | None = None,
|
||||
rows: int | None = None,
|
||||
**kwargs: Any,
|
||||
):
|
||||
@@ -51,9 +50,6 @@ def read_vector(
|
||||
读取后强制重投影到目标 CRS(不传则保留原始 CRS)。
|
||||
encoding:
|
||||
属性表编码,Shapefile 中文路径常需指定 ``"gbk"``。
|
||||
chunk_size:
|
||||
分块大小,默认 None(一次性读取全部数据)。
|
||||
【警告】:若不设置 chunk_size,大文件可能会占用大量内存。
|
||||
rows:
|
||||
限制读取的行数,默认 None(读取全部数据)。
|
||||
用于快速预览数据,避免读取大文件的全部内容。
|
||||
@@ -62,22 +58,15 @@ def read_vector(
|
||||
|
||||
Returns
|
||||
-------
|
||||
gpd.GeoDataFrame 或生成器
|
||||
如果 chunk_size 为 None,返回完整的 GeoDataFrame;
|
||||
如果设置了 chunk_size,返回一个生成器,每次 yield 一个 GeoDataFrame 块。
|
||||
gpd.GeoDataFrame
|
||||
读取的矢量数据。
|
||||
|
||||
示例
|
||||
-----
|
||||
# 全量读取(老方法)
|
||||
### 全量读取
|
||||
gdf = read_vector("data.shp")
|
||||
|
||||
# 分块读取(新方法)
|
||||
for chunk in read_vector("large_data.shp", chunk_size=10000):
|
||||
# 处理每个数据块
|
||||
print(f"处理了 {len(chunk)} 条数据")
|
||||
# 在这里做你的操作,比如计算、过滤等
|
||||
|
||||
# 只读取前 5 行数据(预览模式)
|
||||
### 只读取前 5 行数据(预览模式)
|
||||
gdf_preview = read_vector("large_data.shp", rows=5)
|
||||
print(gdf_preview.head())
|
||||
"""
|
||||
@@ -88,56 +77,13 @@ def read_vector(
|
||||
logger.info("读取矢量数据:%s(格式:%s,图层:%s)", path, suffix or "目录", layer)
|
||||
|
||||
if suffix == ".csv":
|
||||
# CSV 文件暂时不支持分块读取
|
||||
if chunk_size is not None:
|
||||
logger.warning("CSV 文件暂不支持分块读取,将一次性读取全部数据")
|
||||
return _read_csv_vector(path, crs=crs, **kwargs)
|
||||
|
||||
# fiona / geopandas 通用读取
|
||||
read_kwargs: dict[str, Any] = {"encoding": encoding, **kwargs}
|
||||
if layer is not None:
|
||||
read_kwargs["layer"] = layer
|
||||
|
||||
# 分块读取模式
|
||||
if chunk_size is not None:
|
||||
def _chunk_generator():
|
||||
logger.info("启用分块读取模式,每块 %d 条数据", chunk_size)
|
||||
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:
|
||||
read_kwargs["rows"] = rows
|
||||
logger.info("限制读取行数:%d", rows)
|
||||
@@ -151,7 +97,7 @@ def read_vector(
|
||||
gdf = gdf.to_crs(crs) # type: ignore
|
||||
|
||||
logger.info("读取完成:共 %d 条要素,CRS=%s", len(gdf), gdf.crs)
|
||||
return gdf # type: ignore
|
||||
return gdf
|
||||
|
||||
|
||||
# ── 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