跳到主要内容
跳到主要内容

file

一个表引擎,提供类似于表的接口,用于从文件进行 SELECT 和向文件进行 INSERT 操作,类似于 s3 表函数。当处理本地文件时使用 file(),当处理对象存储(如 S3、GCS 或 MinIO)中的存储桶时使用 s3()

file 函数可以用于 SELECTINSERT 查询中,以从文件读取数据或向文件写入数据。

语法

file([path_to_archive ::] path [,format] [,structure] [,compression])

参数

  • path — 从 user_files_path 开始的文件的相对路径。在只读模式下支持以下 glob 模式*?{abc,def}(其中 'abc''def' 是字符串)和 {N..M}(其中 NM 是数字)。
  • path_to_archive - zip/tar/7z 归档文件的相对路径。支持与 path 相同的 glob 模式。
  • format — 文件的格式
  • structure — 表的结构。格式:'column1_name column1_type, column2_name column2_type, ...'
  • compression — 在 SELECT 查询中使用时,表示现有的压缩类型;在 INSERT 查询中使用时,表示期望的压缩类型。支持的压缩类型有 gzbrxzzstlz4bz2

返回值

用于在文件中读取或写入数据的表。

写入文件示例

写入 TSV 文件

INSERT INTO TABLE FUNCTION
file('test.tsv', 'TSV', 'column1 UInt32, column2 UInt32, column3 UInt32')
VALUES (1, 2, 3), (3, 2, 1), (1, 3, 2)

结果,数据被写入到文件 test.tsv

# cat /var/lib/clickhouse/user_files/test.tsv
1 2 3
3 2 1
1 3 2

分区写入到多个 TSV 文件

如果在将数据插入 file() 类型的表函数时指定了 PARTITION BY 表达式,则会为每个分区创建一个单独的文件。将数据拆分到单独的文件中有助于提高读取操作的性能。

INSERT INTO TABLE FUNCTION
file('test_{_partition_id}.tsv', 'TSV', 'column1 UInt32, column2 UInt32, column3 UInt32')
PARTITION BY column3
VALUES (1, 2, 3), (3, 2, 1), (1, 3, 2)

结果,数据被写入到三个文件:test_1.tsvtest_2.tsvtest_3.tsv

# cat /var/lib/clickhouse/user_files/test_1.tsv
3 2 1

# cat /var/lib/clickhouse/user_files/test_2.tsv
1 3 2

# cat /var/lib/clickhouse/user_files/test_3.tsv
1 2 3

从文件读取示例

从 CSV 文件中 SELECT

首先,在服务器配置中设置 user_files_path 并准备文件 test.csv

$ grep user_files_path /etc/clickhouse-server/config.xml
<user_files_path>/var/lib/clickhouse/user_files/</user_files_path>

$ cat /var/lib/clickhouse/user_files/test.csv
1,2,3
3,2,1
78,43,45

然后,从 test.csv 读取数据到表中,并选择其前两行

SELECT * FROM
file('test.csv', 'CSV', 'column1 UInt32, column2 UInt32, column3 UInt32')
LIMIT 2;
┌─column1─┬─column2─┬─column3─┐
│ 1 │ 2 │ 3 │
│ 3 │ 2 │ 1 │
└─────────┴─────────┴─────────┘

从文件向表中插入数据

INSERT INTO FUNCTION
file('test.csv', 'CSV', 'column1 UInt32, column2 UInt32, column3 UInt32')
VALUES (1, 2, 3), (3, 2, 1);
SELECT * FROM
file('test.csv', 'CSV', 'column1 UInt32, column2 UInt32, column3 UInt32');
┌─column1─┬─column2─┬─column3─┐
│ 1 │ 2 │ 3 │
│ 3 │ 2 │ 1 │
└─────────┴─────────┴─────────┘

从位于 archive1.zip 或/和 archive2.zip 中的 table.csv 读取数据

SELECT * FROM file('user_files/archives/archive{1..2}.zip :: table.csv');

路径中的 Glob 模式

路径可以使用 glob 模式。文件必须匹配整个路径模式,而不仅仅是后缀或前缀。有一个例外,如果路径引用的是一个现有目录且未使用 glob 模式,则路径将隐式添加一个 *,以便选择目录中的所有文件。

  • * — 表示任意数量的字符,除了 /,但也包括空字符串。
  • ? — 表示任意单个字符。
  • {some_string,another_string,yet_another_one} — 替换为字符串 'some_string''another_string''yet_another_one' 中的任何一个。这些字符串可以包含 / 符号。
  • {N..M} — 表示任何数字 >= N<= M
  • ** - 递归地表示文件夹内的所有文件。

带有 {} 的构造类似于 remotehdfs 表函数。

示例

假设有以下相对路径的文件

  • some_dir/some_file_1
  • some_dir/some_file_2
  • some_dir/some_file_3
  • another_dir/some_file_1
  • another_dir/some_file_2
  • another_dir/some_file_3

查询所有文件中的总行数

SELECT count(*) FROM file('{some,another}_dir/some_file_{1..3}', 'TSV', 'name String, value UInt32');

实现相同效果的另一种路径表达式

SELECT count(*) FROM file('{some,another}_dir/*', 'TSV', 'name String, value UInt32');

使用隐式 * 查询 some_dir 中的总行数

SELECT count(*) FROM file('some_dir', 'TSV', 'name String, value UInt32');
注意

如果您的文件列表包含带前导零的数字范围,请对每个数字分别使用花括号构造或使用 ?

示例

查询名为 file000, file001, ... , file999 的文件中的总行数

SELECT count(*) FROM file('big_dir/file{0..9}{0..9}{0..9}', 'CSV', 'name String, value UInt32');

示例

递归地查询目录 big_dir/ 内所有文件中的总行数

SELECT count(*) FROM file('big_dir/**', 'CSV', 'name String, value UInt32');

示例

递归地查询目录 big_dir/ 内任何文件夹中所有 file002 文件中的总行数

SELECT count(*) FROM file('big_dir/**/file002', 'CSV', 'name String, value UInt32');

虚拟列

  • _path — 文件的路径。类型:LowCardinality(String)
  • _file — 文件的名称。类型:LowCardinality(String)
  • _size — 文件的大小(字节)。类型:Nullable(UInt64)。如果文件大小未知,则值为 NULL
  • _time — 文件的最后修改时间。类型:Nullable(DateTime)。如果时间未知,则值为 NULL

Hive 风格分区

当设置 use_hive_partitioning 为 1 时,ClickHouse 将检测路径中的 Hive 风格分区 (/name=value/),并允许在查询中使用分区列作为虚拟列。这些虚拟列将具有与分区路径中相同的名称,但以 _ 开头。

示例

使用通过 Hive 风格分区创建的虚拟列

SELECT * from file('data/path/date=*/country=*/code=*/*.parquet') where _date > '2020-01-01' and _country = 'Netherlands' and _code = 42;

设置

另请参阅