Hi All,
This might come in handy, if you are getting errors for a large import of passwords using kdbx format or any other formats.
Export all the passwords into csv format (csv keepass). Then use the following python 3 script to chunk them
split_csv_by_rows.py
#!/usr/bin/env python3
"""
split_csv_by_rows.py
Split a CSV into multiple files, each with a fixed number of rows (default 200).
Preserves header in each output file and never breaks a record across chunks.
"""
import argparse
import csv
import os
import sys
import gzip
def open_output(path, gzip_out=False):
if gzip_out:
return gzip.open(path, "wt", encoding="utf-8", newline='')
return open(path, "w", encoding="utf-8", newline='')
def split_by_rows(input_path, outdir, prefix, rows_per_file, gzip_out=False, quoteall=False):
quoting = csv.QUOTE_ALL if quoteall else csv.QUOTE_MINIMAL
os.makedirs(outdir, exist_ok=True)
with open(input_path, 'r', encoding='utf-8-sig', newline='') as infile:
reader = csv.reader(infile)
try:
header = next(reader)
except StopIteration:
print("Empty file.")
return
file_index = 1
row_count = 0
outfile = None
writer = None
for row in reader:
if row_count % rows_per_file == 0:
# close previous file
if outfile:
outfile.close()
# open new file
out_name = f"{prefix}_{file_index}.csv"
if gzip_out:
out_name += ".gz"
out_path = os.path.join(outdir, out_name)
outfile = open_output(out_path, gzip_out)
writer = csv.writer(outfile, quoting=quoting)
writer.writerow(header) # always write header
print(f"Writing {out_path} ...")
file_index += 1
writer.writerow(row)
row_count += 1
if outfile:
outfile.close()
print("Done.")
def main():
parser = argparse.ArgumentParser(description="Split CSV into chunks of fixed row count (default: 200 rows per file).")
parser.add_argument("input", help="Input CSV file")
parser.add_argument("--rows", "-r", type=int, default=200,
help="Number of data rows per output file (default: 200)")
parser.add_argument("--outdir", "-o", default=".",
help="Output directory (default: current dir)")
parser.add_argument("--prefix", "-p", default="part",
help="Output file prefix (default: part)")
parser.add_argument("--gzip", action="store_true",
help="Compress output files with gzip (.gz)")
parser.add_argument("--quoteall", action="store_true",
help="Force quoting all fields in output")
args = parser.parse_args()
if not os.path.isfile(args.input):
print("ERROR: input file not found:", args.input, file=sys.stderr)
sys.exit(1)
split_by_rows(args.input, args.outdir, args.prefix, args.rows,
gzip_out=args.gzip, quoteall=args.quoteall)
if __name__ == "__main__":
main()
Usage: (default rows 200)
python3 split_csv_by_rows.py passbolt-export-xxxxx.csv --outdir chunks --prefix upload
Custom rows:
python3 split_csv_by_rows.py passbolt-export-xxxxx.csv --rows 100 --outdir chunks --prefix upload
Available arguments:
--rows, -r Number of data rows per output file (default: 200)
--outdir, -o Output directory (default: current dir)
--prefix, -p Output file prefix (default: part)
--gzip Compress output files with gzip (.gz)
--quoteall Force quoting all fields in output
You’ll thank me later.
Enjoy