[{"data":1,"prerenderedAt":2224},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-csv-files-to-excel-with-python":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-csv-files-to-excel-with-python":2190,"ancestors:\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-csv-files-to-excel-with-python":2199,"children:\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-csv-files-to-excel-with-python":2204,"related:\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-csv-files-to-excel-with-python":2205},{"id":4,"title":5,"body":6,"dateModified":2155,"datePublished":2155,"description":2156,"extension":2157,"faq":2158,"keyword":2167,"kind":2168,"meta":2169,"navigation":223,"path":2178,"seo":2179,"slug":2182,"stem":2183,"topics":2184,"type":2188,"__hash__":2189},"docs\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-csv-files-to-excel-with-python\u002Findex.md","Convert CSV Files to Excel with Python",{"type":7,"value":8,"toc":2141},"minimark",[9,19,158,163,192,195,377,381,384,510,528,532,535,818,824,828,844,904,915,1071,1075,1078,1331,1347,1351,1358,1632,1640,1754,1758,1761,1998,2001,2005,2054,2058,2069,2073,2076,2080,2086,2092,2098,2104,2108,2137],[10,11,12,13,18],"p",{},"CSV is how most systems export data, and Excel is how most people want to receive it. Opening a CSV directly in Excel is the source of many familiar problems — dates flipped between day and month, codes stripped of their leading zeros, accented names garbled — because Excel guesses at every column. Converting with Python moves those decisions into code, where they are made once, explicitly, for every file. This guide, part of ",[14,15,17],"a",{"href":16},"\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002F","Handling Excel File Formats and Conversions",", converts single files and folders of files, and handles the limits Excel imposes on the result.",[20,21,29,30,29,34,29,38,29,46,29,56,29,67,29,74,29,79,29,85,29,91,29,97,29,102,29,106,29,111,29,114,29,119,29,122,29,126,29,129,29,131,29,134,29,139,29,143,29,147,29,150,29,152],"svg",{"viewBox":22,"role":23,"ariaLabelledBy":24,"xmlns":27,"style":28},"4 0 752 358","img",[25,26],"csv-fan-t","csv-fan-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[31,32,33],"title",{"id":25},"A folder of CSV exports combined into one workbook",[35,36,37],"desc",{"id":26},"Three monthly CSV exports are each read with explicit encoding, delimiter and column types, then written as one sheet each in a single Excel workbook named after the quarter.",[39,40],"rect",{"x":41,"y":42,"width":43,"height":44,"fill":45},"4","0","752","358","#ffffff",[39,47],{"x":48,"y":49,"width":50,"height":51,"rx":52,"fill":53,"stroke":54,"style":55},"520.0","119.5","220.0","93.0","12","#d9f4f1","var(--teal,#0f9488)","stroke-width:2px",[57,58,60],"g",{"transform":59},"translate(618.0,132.5) scale(1.000)",[61,62],"path",{"d":63,"fill":64,"stroke":65,"style":66},"M6 3h9l4 4v14H6z M15 3v4h4 M9.5 11.5l4.5 6 M14 11.5l-4.5 6","none","var(--teal-ink,#0b6157)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[68,69,73],"text",{"x":70,"y":71,"style":72},"630.0","179.0","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","sales_q1.xlsx",[68,75,78],{"x":70,"y":76,"style":77},"198.5","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","one sheet per CSV",[39,80],{"x":81,"y":82,"width":83,"height":84,"rx":52,"fill":53,"stroke":54,"style":55},"20.0","16.0","250.0","92.0",[57,86,88],{"transform":87},"translate(133.0,29.0) scale(1.000)",[61,89],{"d":90,"fill":64,"stroke":65,"style":66},"M6 3h9l4 4v14H6z M15 3v4h4",[68,92,96],{"x":93,"y":94,"style":95},"145.0","75.0","font-size:13px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","sales_2026_01.csv",[68,98,101],{"x":93,"y":99,"style":100},"94.0","font-size:11px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","UTF-8, comma",[61,103],{"d":104,"fill":64,"stroke":105,"style":55},"M274.0,62.0 C394.0,62.0 394.0,166.0 510.0,166.0","var(--brand,#5b5cf0)",[107,108],"polygon",{"points":109,"fill":110},"514.0,166.0 505.0,171.0 505.0,161.0","#5b5cf0",[39,112],{"x":81,"y":113,"width":83,"height":84,"rx":52,"fill":53,"stroke":54,"style":55},"120.0",[57,115,117],{"transform":116},"translate(133.0,133.0) scale(1.000)",[61,118],{"d":90,"fill":64,"stroke":65,"style":66},[68,120,121],{"x":93,"y":71,"style":95},"sales_2026_02.csv",[68,123,125],{"x":93,"y":124,"style":100},"198.0","cp1252, comma",[61,127],{"d":128,"fill":64,"stroke":105,"style":55},"M274.0,166.0 C394.0,166.0 394.0,166.0 510.0,166.0",[107,130],{"points":109,"fill":110},[39,132],{"x":81,"y":133,"width":83,"height":84,"rx":52,"fill":53,"stroke":54,"style":55},"224.0",[57,135,137],{"transform":136},"translate(133.0,237.0) scale(1.000)",[61,138],{"d":90,"fill":64,"stroke":65,"style":66},[68,140,142],{"x":93,"y":141,"style":95},"283.0","sales_2026_03.csv",[68,144,146],{"x":93,"y":145,"style":100},"302.0","UTF-8, semicolon",[61,148],{"d":149,"fill":64,"stroke":105,"style":55},"M274.0,270.0 C394.0,270.0 394.0,166.0 510.0,166.0",[107,151],{"points":109,"fill":110},[68,153,157],{"x":154,"y":155,"style":156},"380.0","338.0","font-size:12.5px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle","every file is read with explicit settings, so no column is left to Excel's guesswork",[159,160,162],"h2",{"id":161},"prerequisites","Prerequisites",[164,165,170],"pre",{"className":166,"code":167,"language":168,"meta":169,"style":169},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas xlsxwriter\n","bash","",[171,172,173],"code",{"__ignoreMap":169},[174,175,178,182,186,189],"span",{"class":176,"line":177},"line",1,[174,179,181],{"class":180},"sMTad","pip",[174,183,185],{"class":184},"srMev"," install",[174,187,188],{"class":184}," pandas",[174,190,191],{"class":184}," xlsxwriter\n",[10,193,194],{},"The examples create three small CSVs that behave like real exports — different encodings, one with semicolons, and a code column with leading zeros:",[164,196,200],{"className":197,"code":198,"language":199,"meta":169,"style":169},"language-python shiki shiki-themes github-light github-dark-high-contrast","from pathlib import Path\n\nPath(\"exports\").mkdir(exist_ok=True)\nPath(\"exports\u002Fsales_2026_01.csv\").write_text(\n    \"customer_id,name,order_date,amount\\n00123,Zoë Adams,2026-01-05,1200.50\\n00456,Ben Okafor,2026-01-19,980.00\\n\",\n    encoding=\"utf-8\")\nPath(\"exports\u002Fsales_2026_02.csv\").write_text(\n    \"customer_id,name,order_date,amount\\n00789,José Núñez,2026-02-02,455.25\\n\",\n    encoding=\"cp1252\")\nPath(\"exports\u002Fsales_2026_03.csv\").write_text(\n    \"customer_id;name;order_date;amount\\n00123;Zoë Adams;2026-03-11;310,00\\n\",\n    encoding=\"utf-8\")\n","python",[171,201,202,218,225,251,262,288,301,311,327,339,349,366],{"__ignoreMap":169},[174,203,204,208,212,215],{"class":176,"line":177},[174,205,207],{"class":206},"s-kum","from",[174,209,211],{"class":210},"skGVy"," pathlib ",[174,213,214],{"class":206},"import",[174,216,217],{"class":210}," Path\n",[174,219,221],{"class":176,"line":220},2,[174,222,224],{"emptyLinePlaceholder":223},true,"\n",[174,226,228,231,234,237,241,244,248],{"class":176,"line":227},3,[174,229,230],{"class":210},"Path(",[174,232,233],{"class":184},"\"exports\"",[174,235,236],{"class":210},").mkdir(",[174,238,240],{"class":239},"sa561","exist_ok",[174,242,243],{"class":206},"=",[174,245,247],{"class":246},"sP0c6","True",[174,249,250],{"class":210},")\n",[174,252,254,256,259],{"class":176,"line":253},4,[174,255,230],{"class":210},[174,257,258],{"class":184},"\"exports\u002Fsales_2026_01.csv\"",[174,260,261],{"class":210},").write_text(\n",[174,263,265,268,272,275,277,280,282,285],{"class":176,"line":264},5,[174,266,267],{"class":184},"    \"customer_id,name,order_date,amount",[174,269,271],{"class":270},"sSjpA","\\n",[174,273,274],{"class":184},"00123,Zoë Adams,2026-01-05,1200.50",[174,276,271],{"class":270},[174,278,279],{"class":184},"00456,Ben Okafor,2026-01-19,980.00",[174,281,271],{"class":270},[174,283,284],{"class":184},"\"",[174,286,287],{"class":210},",\n",[174,289,291,294,296,299],{"class":176,"line":290},6,[174,292,293],{"class":239},"    encoding",[174,295,243],{"class":206},[174,297,298],{"class":184},"\"utf-8\"",[174,300,250],{"class":210},[174,302,304,306,309],{"class":176,"line":303},7,[174,305,230],{"class":210},[174,307,308],{"class":184},"\"exports\u002Fsales_2026_02.csv\"",[174,310,261],{"class":210},[174,312,314,316,318,321,323,325],{"class":176,"line":313},8,[174,315,267],{"class":184},[174,317,271],{"class":270},[174,319,320],{"class":184},"00789,José Núñez,2026-02-02,455.25",[174,322,271],{"class":270},[174,324,284],{"class":184},[174,326,287],{"class":210},[174,328,330,332,334,337],{"class":176,"line":329},9,[174,331,293],{"class":239},[174,333,243],{"class":206},[174,335,336],{"class":184},"\"cp1252\"",[174,338,250],{"class":210},[174,340,342,344,347],{"class":176,"line":341},10,[174,343,230],{"class":210},[174,345,346],{"class":184},"\"exports\u002Fsales_2026_03.csv\"",[174,348,261],{"class":210},[174,350,352,355,357,360,362,364],{"class":176,"line":351},11,[174,353,354],{"class":184},"    \"customer_id;name;order_date;amount",[174,356,271],{"class":270},[174,358,359],{"class":184},"00123;Zoë Adams;2026-03-11;310,00",[174,361,271],{"class":270},[174,363,284],{"class":184},[174,365,287],{"class":210},[174,367,369,371,373,375],{"class":176,"line":368},12,[174,370,293],{"class":239},[174,372,243],{"class":206},[174,374,298],{"class":184},[174,376,250],{"class":210},[159,378,380],{"id":379},"step-1-convert-one-file-with-explicit-types","Step 1 — Convert one file, with explicit types",[10,382,383],{},"The one-liner works, but it lets pandas infer every type. State the ones that matter: identifiers as text, dates as dates.",[164,385,387],{"className":197,"code":386,"language":199,"meta":169,"style":169},"import pandas as pd\n\ndf = pd.read_csv(\n    \"exports\u002Fsales_2026_01.csv\",\n    dtype={\"customer_id\": str},\n    parse_dates=[\"order_date\"],\n)\ndf.to_excel(\"sales_2026_01.xlsx\", index=False)\nprint(df.dtypes)\nprint(df[\"customer_id\"].tolist())   # ['00123', '00456']\n",[171,388,389,402,406,416,423,445,461,465,486,494],{"__ignoreMap":169},[174,390,391,393,396,399],{"class":176,"line":177},[174,392,214],{"class":206},[174,394,395],{"class":210}," pandas ",[174,397,398],{"class":206},"as",[174,400,401],{"class":210}," pd\n",[174,403,404],{"class":176,"line":220},[174,405,224],{"emptyLinePlaceholder":223},[174,407,408,411,413],{"class":176,"line":227},[174,409,410],{"class":210},"df ",[174,412,243],{"class":206},[174,414,415],{"class":210}," pd.read_csv(\n",[174,417,418,421],{"class":176,"line":253},[174,419,420],{"class":184},"    \"exports\u002Fsales_2026_01.csv\"",[174,422,287],{"class":210},[174,424,425,428,430,433,436,439,442],{"class":176,"line":264},[174,426,427],{"class":239},"    dtype",[174,429,243],{"class":206},[174,431,432],{"class":210},"{",[174,434,435],{"class":184},"\"customer_id\"",[174,437,438],{"class":210},": ",[174,440,441],{"class":246},"str",[174,443,444],{"class":210},"},\n",[174,446,447,450,452,455,458],{"class":176,"line":290},[174,448,449],{"class":239},"    parse_dates",[174,451,243],{"class":206},[174,453,454],{"class":210},"[",[174,456,457],{"class":184},"\"order_date\"",[174,459,460],{"class":210},"],\n",[174,462,463],{"class":176,"line":303},[174,464,250],{"class":210},[174,466,467,470,473,476,479,481,484],{"class":176,"line":313},[174,468,469],{"class":210},"df.to_excel(",[174,471,472],{"class":184},"\"sales_2026_01.xlsx\"",[174,474,475],{"class":210},", ",[174,477,478],{"class":239},"index",[174,480,243],{"class":206},[174,482,483],{"class":246},"False",[174,485,250],{"class":210},[174,487,488,491],{"class":176,"line":329},[174,489,490],{"class":246},"print",[174,492,493],{"class":210},"(df.dtypes)\n",[174,495,496,498,501,503,506],{"class":176,"line":341},[174,497,490],{"class":246},[174,499,500],{"class":210},"(df[",[174,502,435],{"class":184},[174,504,505],{"class":210},"].tolist())   ",[174,507,509],{"class":508},"s-wDw","# ['00123', '00456']\n",[10,511,512,515,516,519,520,523,524,527],{},[171,513,514],{},"dtype={\"customer_id\": str}"," keeps ",[171,517,518],{},"00123"," intact — read as a number it would become ",[171,521,522],{},"123",", and a lookup against a customer list keyed on text would miss every row. ",[171,525,526],{},"index=False"," stops pandas from writing its row numbers as an extra first column.",[159,529,531],{"id":530},"step-2-detect-the-encoding-and-the-delimiter","Step 2 — Detect the encoding and the delimiter",[10,533,534],{},"Exports from different systems disagree on both. A small reader that tries the likely encodings in order and lets Python's CSV sniffer choose the delimiter copes with most of them:",[164,536,538],{"className":197,"code":537,"language":199,"meta":169,"style":169},"import csv\n\ndef read_export(path, **kwargs) -> pd.DataFrame:\n    raw = Path(path).read_bytes()\n    for encoding in (\"utf-8-sig\", \"cp1252\"):\n        try:\n            text = raw.decode(encoding)\n            break\n        except UnicodeDecodeError:\n            continue\n    else:\n        raise ValueError(f\"{path}: not UTF-8 or Windows-1252\")\n    dialect = csv.Sniffer().sniff(text.splitlines()[0], delimiters=\",;\\t|\")\n    return pd.read_csv(path, encoding=encoding, sep=dialect.delimiter, **kwargs)\n\nfor f in sorted(Path(\"exports\").glob(\"*.csv\")):\n    frame = read_export(f, dtype={\"customer_id\": str})\n    print(f.name, frame.shape, frame[\"name\"].iloc[0])\n",[171,539,540,547,551,569,579,603,611,621,626,636,641,648,676,708,738,743,771,798],{"__ignoreMap":169},[174,541,542,544],{"class":176,"line":177},[174,543,214],{"class":206},[174,545,546],{"class":210}," csv\n",[174,548,549],{"class":176,"line":220},[174,550,224],{"emptyLinePlaceholder":223},[174,552,553,556,560,563,566],{"class":176,"line":227},[174,554,555],{"class":206},"def",[174,557,559],{"class":558},"s_Opv"," read_export",[174,561,562],{"class":210},"(path, ",[174,564,565],{"class":206},"**",[174,567,568],{"class":210},"kwargs) -> pd.DataFrame:\n",[174,570,571,574,576],{"class":176,"line":253},[174,572,573],{"class":210},"    raw ",[174,575,243],{"class":206},[174,577,578],{"class":210}," Path(path).read_bytes()\n",[174,580,581,584,587,590,593,596,598,600],{"class":176,"line":264},[174,582,583],{"class":206},"    for",[174,585,586],{"class":210}," encoding ",[174,588,589],{"class":206},"in",[174,591,592],{"class":210}," (",[174,594,595],{"class":184},"\"utf-8-sig\"",[174,597,475],{"class":210},[174,599,336],{"class":184},[174,601,602],{"class":210},"):\n",[174,604,605,608],{"class":176,"line":290},[174,606,607],{"class":206},"        try",[174,609,610],{"class":210},":\n",[174,612,613,616,618],{"class":176,"line":303},[174,614,615],{"class":210},"            text ",[174,617,243],{"class":206},[174,619,620],{"class":210}," raw.decode(encoding)\n",[174,622,623],{"class":176,"line":313},[174,624,625],{"class":206},"            break\n",[174,627,628,631,634],{"class":176,"line":329},[174,629,630],{"class":206},"        except",[174,632,633],{"class":246}," UnicodeDecodeError",[174,635,610],{"class":210},[174,637,638],{"class":176,"line":341},[174,639,640],{"class":206},"            continue\n",[174,642,643,646],{"class":176,"line":351},[174,644,645],{"class":206},"    else",[174,647,610],{"class":210},[174,649,650,653,656,659,662,664,666,668,671,674],{"class":176,"line":368},[174,651,652],{"class":206},"        raise",[174,654,655],{"class":246}," ValueError",[174,657,658],{"class":210},"(",[174,660,661],{"class":206},"f",[174,663,284],{"class":184},[174,665,432],{"class":270},[174,667,61],{"class":210},[174,669,670],{"class":270},"}",[174,672,673],{"class":184},": not UTF-8 or Windows-1252\"",[174,675,250],{"class":210},[174,677,679,682,684,687,689,692,695,697,700,703,706],{"class":176,"line":678},13,[174,680,681],{"class":210},"    dialect ",[174,683,243],{"class":206},[174,685,686],{"class":210}," csv.Sniffer().sniff(text.splitlines()[",[174,688,42],{"class":246},[174,690,691],{"class":210},"], ",[174,693,694],{"class":239},"delimiters",[174,696,243],{"class":206},[174,698,699],{"class":184},"\",;",[174,701,702],{"class":270},"\\t",[174,704,705],{"class":184},"|\"",[174,707,250],{"class":210},[174,709,711,714,717,720,722,725,728,730,733,735],{"class":176,"line":710},14,[174,712,713],{"class":206},"    return",[174,715,716],{"class":210}," pd.read_csv(path, ",[174,718,719],{"class":239},"encoding",[174,721,243],{"class":206},[174,723,724],{"class":210},"encoding, ",[174,726,727],{"class":239},"sep",[174,729,243],{"class":206},[174,731,732],{"class":210},"dialect.delimiter, ",[174,734,565],{"class":206},[174,736,737],{"class":210},"kwargs)\n",[174,739,741],{"class":176,"line":740},15,[174,742,224],{"emptyLinePlaceholder":223},[174,744,746,749,752,754,757,760,762,765,768],{"class":176,"line":745},16,[174,747,748],{"class":206},"for",[174,750,751],{"class":210}," f ",[174,753,589],{"class":206},[174,755,756],{"class":246}," sorted",[174,758,759],{"class":210},"(Path(",[174,761,233],{"class":184},[174,763,764],{"class":210},").glob(",[174,766,767],{"class":184},"\"*.csv\"",[174,769,770],{"class":210},")):\n",[174,772,774,777,779,782,785,787,789,791,793,795],{"class":176,"line":773},17,[174,775,776],{"class":210},"    frame ",[174,778,243],{"class":206},[174,780,781],{"class":210}," read_export(f, ",[174,783,784],{"class":239},"dtype",[174,786,243],{"class":206},[174,788,432],{"class":210},[174,790,435],{"class":184},[174,792,438],{"class":210},[174,794,441],{"class":246},[174,796,797],{"class":210},"})\n",[174,799,801,804,807,810,813,815],{"class":176,"line":800},18,[174,802,803],{"class":246},"    print",[174,805,806],{"class":210},"(f.name, frame.shape, frame[",[174,808,809],{"class":184},"\"name\"",[174,811,812],{"class":210},"].iloc[",[174,814,42],{"class":246},[174,816,817],{"class":210},"])\n",[10,819,820,823],{},[171,821,822],{},"utf-8-sig"," comes first because it reads plain UTF-8 and also strips the byte-order mark that Excel adds when it saves \"CSV UTF-8\". Windows-1252 is the usual fallback for files saved by older Excel on Windows. Order matters: almost any bytes decode as Windows-1252, so trying it first would \"succeed\" on UTF-8 files and garble them.",[159,825,827],{"id":826},"step-3-fix-decimal-commas","Step 3 — Fix decimal commas",[10,829,830,831,835,836,839,840,843],{},"The March file uses semicolons ",[832,833,834],"em",{},"and"," a decimal comma (",[171,837,838],{},"310,00",") — the European convention. Tell ",[171,841,842],{},"read_csv"," about both, and the amount arrives as a number:",[164,845,847],{"className":197,"code":846,"language":199,"meta":169,"style":169},"march = read_export(\"exports\u002Fsales_2026_03.csv\", dtype={\"customer_id\": str}, decimal=\",\")\nprint(march[\"amount\"].tolist())    # [310.0]\n",[171,848,849,888],{"__ignoreMap":169},[174,850,851,854,856,859,861,863,865,867,869,871,873,875,878,881,883,886],{"class":176,"line":177},[174,852,853],{"class":210},"march ",[174,855,243],{"class":206},[174,857,858],{"class":210}," read_export(",[174,860,346],{"class":184},[174,862,475],{"class":210},[174,864,784],{"class":239},[174,866,243],{"class":206},[174,868,432],{"class":210},[174,870,435],{"class":184},[174,872,438],{"class":210},[174,874,441],{"class":246},[174,876,877],{"class":210},"}, ",[174,879,880],{"class":239},"decimal",[174,882,243],{"class":206},[174,884,885],{"class":184},"\",\"",[174,887,250],{"class":210},[174,889,890,892,895,898,901],{"class":176,"line":220},[174,891,490],{"class":246},[174,893,894],{"class":210},"(march[",[174,896,897],{"class":184},"\"amount\"",[174,899,900],{"class":210},"].tolist())    ",[174,902,903],{"class":508},"# [310.0]\n",[10,905,906,907,910,911,914],{},"Pass ",[171,908,909],{},"decimal=\",\""," only for files that use it: applied to a comma-delimited file with ordinary decimals it does nothing useful, and applied to a semicolon file with thousands separators you also need ",[171,912,913],{},"thousands=\".\"",". Knowing each source's conventions and recording them in code is what makes the conversion reliable.",[20,916,29,921,29,924,29,927,29,930,29,938,29,944,29,947,29,952,29,955,29,959,29,964,29,968,29,972,29,976,29,981,29,985,29,989,29,993,29,997,29,1000,29,1004,29,1006,29,1010,29,1012,29,1015,29,1017,29,1020,29,1022,29,1025,29,1027,29,1030,29,1032,29,1035,29,1037,29,1040,29,1046,29,1050,29,1054,29,1057,29,1065],{"viewBox":917,"role":23,"ariaLabelledBy":918,"xmlns":27,"style":28},"4 0 752 136",[919,920],"csv-types-t","csv-types-d",[31,922,923],{"id":919},"A European CSV read with explicit settings",[35,925,926],{"id":920},"The raw file uses semicolons between fields and a comma as the decimal mark, and the customer ID has leading zeros. Read with sep semicolon, decimal comma and customer_id as text, the result has the ID intact and the amount as the number 310.",[39,928],{"x":41,"y":42,"width":43,"height":929,"fill":45},"136",[39,931],{"x":81,"y":932,"width":933,"height":934,"rx":42,"fill":935,"stroke":936,"style":937},"40.0","32.0","28.0","#e7ebef","var(--line,#cdd5e6)","stroke-width:1px",[68,939,943],{"x":940,"y":941,"style":942},"36.0","59.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","1",[39,945],{"x":946,"y":932,"width":71,"height":934,"rx":42,"fill":45,"stroke":936,"style":937},"52.0",[68,948,951],{"x":949,"y":941,"style":950},"141.5","font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","customer_id;name;…;amount",[39,953],{"x":81,"y":954,"width":933,"height":934,"rx":42,"fill":935,"stroke":936,"style":937},"68.0",[68,956,958],{"x":940,"y":957,"style":942},"87.0","2",[39,960],{"x":946,"y":954,"width":71,"height":934,"rx":42,"fill":961,"stroke":962,"style":963},"#fee8f2","var(--accent,#f43f8f)","stroke-width:1.5px",[68,965,967],{"x":949,"y":957,"style":966},"font-size:12px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","00123;Zoë Adams;…;310,00",[39,969],{"x":970,"y":932,"width":933,"height":971,"rx":42,"fill":935,"stroke":936,"style":937},"477.7","24.0",[39,973],{"x":974,"y":932,"width":975,"height":971,"rx":42,"fill":935,"stroke":936,"style":937},"509.7","87.1",[68,977,980],{"x":978,"y":979,"style":942},"553.2","57.0","A",[39,982],{"x":983,"y":932,"width":984,"height":971,"rx":42,"fill":935,"stroke":936,"style":937},"596.8","81.6",[68,986,988],{"x":987,"y":979,"style":942},"637.6","B",[39,990],{"x":991,"y":932,"width":992,"height":971,"rx":42,"fill":935,"stroke":936,"style":937},"678.4","61.6",[68,994,996],{"x":995,"y":979,"style":942},"709.2","C",[39,998],{"x":970,"y":999,"width":933,"height":934,"rx":42,"fill":935,"stroke":936,"style":937},"64.0",[68,1001,943],{"x":1002,"y":1003,"style":942},"493.7","83.0",[39,1005],{"x":974,"y":999,"width":975,"height":934,"rx":42,"fill":45,"stroke":936,"style":937},[68,1007,1009],{"x":978,"y":1003,"style":1008},"font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","customer_id",[39,1011],{"x":983,"y":999,"width":984,"height":934,"rx":42,"fill":45,"stroke":936,"style":937},[68,1013,1014],{"x":987,"y":1003,"style":1008},"name",[39,1016],{"x":991,"y":999,"width":992,"height":934,"rx":42,"fill":45,"stroke":936,"style":937},[68,1018,1019],{"x":995,"y":1003,"style":1008},"amount",[39,1021],{"x":970,"y":84,"width":933,"height":934,"rx":42,"fill":935,"stroke":936,"style":937},[68,1023,958],{"x":1002,"y":1024,"style":942},"111.0",[39,1026],{"x":974,"y":84,"width":975,"height":934,"rx":42,"fill":53,"stroke":54,"style":963},[68,1028,518],{"x":978,"y":1024,"style":1029},"font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle",[39,1031],{"x":983,"y":84,"width":984,"height":934,"rx":42,"fill":45,"stroke":936,"style":937},[68,1033,1034],{"x":987,"y":1024,"style":950},"Zoë Adams",[39,1036],{"x":991,"y":84,"width":992,"height":934,"rx":42,"fill":53,"stroke":54,"style":963},[68,1038,1039],{"x":995,"y":1024,"style":1029},"310.0",[68,1041,1045],{"x":1042,"y":1043,"style":1044},"125.5","29.0","font-size:12.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","raw CSV text",[68,1047,1049],{"x":1048,"y":1043,"style":1044},"608.9","DataFrame",[176,1051],{"x1":1052,"y1":954,"x2":1053,"y2":954,"stroke":105,"style":55},"241.0","463.7",[107,1055],{"points":1056,"fill":110},"467.7,68.0 458.7,73.0 458.7,63.0",[39,1058],{"x":1059,"y":1060,"width":1061,"height":1062,"rx":1063,"fill":45,"stroke":936,"style":1064},"271.6","35.0","165.4","22.0","11","stroke-width:1.2px",[68,1066,1070],{"x":1067,"y":1068,"style":1069},"354.3","50.0","font-size:11.5px;font-weight:400;fill:var(--brand-strong,#4338ca);text-anchor:middle;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace","sep=';', decimal=','",[159,1072,1074],{"id":1073},"step-4-many-csvs-one-workbook","Step 4 — Many CSVs, one workbook",[10,1076,1077],{},"Readers usually want one workbook, not a folder of them. Write each CSV to its own sheet, named after the file, through a single writer:",[164,1079,1081],{"className":197,"code":1080,"language":199,"meta":169,"style":169},"with pd.ExcelWriter(\"sales_q1.xlsx\", engine=\"xlsxwriter\", datetime_format=\"yyyy-mm-dd\") as writer:\n    for f in sorted(Path(\"exports\").glob(\"*.csv\")):\n        decimal = \",\" if f.name.endswith(\"_03.csv\") else \".\"\n        frame = read_export(f, dtype={\"customer_id\": str}, parse_dates=[\"order_date\"], decimal=decimal)\n        sheet = f.stem.replace(\"sales_\", \"\")[:31]          # '2026_01'\n        frame.to_excel(writer, sheet_name=sheet, index=False)\n        ws = writer.sheets[sheet]\n        ws.freeze_panes(1, 0)\n        ws.set_column(0, len(frame.columns) - 1, 16)\n\nprint(pd.ExcelFile(\"sales_q1.xlsx\").sheet_names)   # ['2026_01', '2026_02', '2026_03']\n",[171,1082,1083,1122,1142,1169,1210,1240,1261,1271,1284,1312,1316],{"__ignoreMap":169},[174,1084,1085,1088,1091,1094,1096,1099,1101,1104,1106,1109,1111,1114,1117,1119],{"class":176,"line":177},[174,1086,1087],{"class":206},"with",[174,1089,1090],{"class":210}," pd.ExcelWriter(",[174,1092,1093],{"class":184},"\"sales_q1.xlsx\"",[174,1095,475],{"class":210},[174,1097,1098],{"class":239},"engine",[174,1100,243],{"class":206},[174,1102,1103],{"class":184},"\"xlsxwriter\"",[174,1105,475],{"class":210},[174,1107,1108],{"class":239},"datetime_format",[174,1110,243],{"class":206},[174,1112,1113],{"class":184},"\"yyyy-mm-dd\"",[174,1115,1116],{"class":210},") ",[174,1118,398],{"class":206},[174,1120,1121],{"class":210}," writer:\n",[174,1123,1124,1126,1128,1130,1132,1134,1136,1138,1140],{"class":176,"line":220},[174,1125,583],{"class":206},[174,1127,751],{"class":210},[174,1129,589],{"class":206},[174,1131,756],{"class":246},[174,1133,759],{"class":210},[174,1135,233],{"class":184},[174,1137,764],{"class":210},[174,1139,767],{"class":184},[174,1141,770],{"class":210},[174,1143,1144,1147,1149,1152,1155,1158,1161,1163,1166],{"class":176,"line":227},[174,1145,1146],{"class":210},"        decimal ",[174,1148,243],{"class":206},[174,1150,1151],{"class":184}," \",\"",[174,1153,1154],{"class":206}," if",[174,1156,1157],{"class":210}," f.name.endswith(",[174,1159,1160],{"class":184},"\"_03.csv\"",[174,1162,1116],{"class":210},[174,1164,1165],{"class":206},"else",[174,1167,1168],{"class":184}," \".\"\n",[174,1170,1171,1174,1176,1178,1180,1182,1184,1186,1188,1190,1192,1195,1197,1199,1201,1203,1205,1207],{"class":176,"line":253},[174,1172,1173],{"class":210},"        frame ",[174,1175,243],{"class":206},[174,1177,781],{"class":210},[174,1179,784],{"class":239},[174,1181,243],{"class":206},[174,1183,432],{"class":210},[174,1185,435],{"class":184},[174,1187,438],{"class":210},[174,1189,441],{"class":246},[174,1191,877],{"class":210},[174,1193,1194],{"class":239},"parse_dates",[174,1196,243],{"class":206},[174,1198,454],{"class":210},[174,1200,457],{"class":184},[174,1202,691],{"class":210},[174,1204,880],{"class":239},[174,1206,243],{"class":206},[174,1208,1209],{"class":210},"decimal)\n",[174,1211,1212,1215,1217,1220,1223,1225,1228,1231,1234,1237],{"class":176,"line":264},[174,1213,1214],{"class":210},"        sheet ",[174,1216,243],{"class":206},[174,1218,1219],{"class":210}," f.stem.replace(",[174,1221,1222],{"class":184},"\"sales_\"",[174,1224,475],{"class":210},[174,1226,1227],{"class":184},"\"\"",[174,1229,1230],{"class":210},")[:",[174,1232,1233],{"class":246},"31",[174,1235,1236],{"class":210},"]          ",[174,1238,1239],{"class":508},"# '2026_01'\n",[174,1241,1242,1245,1248,1250,1253,1255,1257,1259],{"class":176,"line":290},[174,1243,1244],{"class":210},"        frame.to_excel(writer, ",[174,1246,1247],{"class":239},"sheet_name",[174,1249,243],{"class":206},[174,1251,1252],{"class":210},"sheet, ",[174,1254,478],{"class":239},[174,1256,243],{"class":206},[174,1258,483],{"class":246},[174,1260,250],{"class":210},[174,1262,1263,1266,1268],{"class":176,"line":303},[174,1264,1265],{"class":210},"        ws ",[174,1267,243],{"class":206},[174,1269,1270],{"class":210}," writer.sheets[sheet]\n",[174,1272,1273,1276,1278,1280,1282],{"class":176,"line":313},[174,1274,1275],{"class":210},"        ws.freeze_panes(",[174,1277,943],{"class":246},[174,1279,475],{"class":210},[174,1281,42],{"class":246},[174,1283,250],{"class":210},[174,1285,1286,1289,1291,1293,1296,1299,1302,1305,1307,1310],{"class":176,"line":329},[174,1287,1288],{"class":210},"        ws.set_column(",[174,1290,42],{"class":246},[174,1292,475],{"class":210},[174,1294,1295],{"class":246},"len",[174,1297,1298],{"class":210},"(frame.columns) ",[174,1300,1301],{"class":206},"-",[174,1303,1304],{"class":246}," 1",[174,1306,475],{"class":210},[174,1308,1309],{"class":246},"16",[174,1311,250],{"class":210},[174,1313,1314],{"class":176,"line":341},[174,1315,224],{"emptyLinePlaceholder":223},[174,1317,1318,1320,1323,1325,1328],{"class":176,"line":351},[174,1319,490],{"class":246},[174,1321,1322],{"class":210},"(pd.ExcelFile(",[174,1324,1093],{"class":184},[174,1326,1327],{"class":210},").sheet_names)   ",[174,1329,1330],{"class":508},"# ['2026_01', '2026_02', '2026_03']\n",[10,1332,1333,1334,1337,1338,1342,1343,1346],{},"Sheet names are limited to 31 characters and may not contain ",[171,1335,1336],{},"[ ] : * ? \u002F \\","; a file name is usually safe after trimming, but see ",[14,1339,1341],{"href":1340},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-multiple-excel-sheets-in-python\u002Fcreate-a-sheet-for-each-group-in-a-dataframe\u002F","Create a Sheet for Each Group in a DataFrame"," for a helper that cleans and de-duplicates arbitrary names. If the files share columns and should be one table rather than several sheets, concatenate them first with a ",[171,1344,1345],{},"source_file"," column instead. One long table is easier to filter, pivot and chart than a dozen tabs with identical headers, and it reads back into pandas in a single call; separate sheets suit readers who look at one period at a time.",[159,1348,1350],{"id":1349},"step-5-files-bigger-than-one-sheet","Step 5 — Files bigger than one sheet",[10,1352,1353,1354,1357],{},"An Excel sheet holds 1,048,576 rows ",[832,1355,1356],{},"including the header",", so 1,048,575 data rows at most. pandas checks the data rows against the full limit, which leaves an off-by-one gap: a frame of exactly 1,048,576 rows passes the check, and the xlsxwriter engine then writes the header plus every row but the last — silently. The last row is simply missing. Check the limit yourself and split large files across sheets:",[164,1359,1361],{"className":197,"code":1360,"language":199,"meta":169,"style":169},"MAX_DATA_ROWS = 1_048_576 - 1          # one row is the header\n\ndef write_split(frame: pd.DataFrame, path: str, base: str = \"data\") -> list[str]:\n    names = []\n    with pd.ExcelWriter(path, engine=\"xlsxwriter\") as writer:\n        for part, start in enumerate(range(0, len(frame), MAX_DATA_ROWS), start=1):\n            name = f\"{base}_{part}\"\n            frame.iloc[start:start + MAX_DATA_ROWS].to_excel(writer, sheet_name=name, index=False)\n            names.append(name)\n    return names\n\nsmall_demo = pd.DataFrame({\"n\": range(10)})\nMAX_DATA_ROWS = 4                       # tiny limit just to show the split\nprint(write_split(small_demo, \"split_demo.xlsx\"))   # ['data_1', 'data_2', 'data_3']\nMAX_DATA_ROWS = 1_048_576 - 1\n",[171,1362,1363,1382,1386,1416,1426,1446,1489,1521,1550,1555,1562,1566,1591,1603,1619],{"__ignoreMap":169},[174,1364,1365,1368,1371,1374,1377,1379],{"class":176,"line":177},[174,1366,1367],{"class":246},"MAX_DATA_ROWS",[174,1369,1370],{"class":206}," =",[174,1372,1373],{"class":246}," 1_048_576",[174,1375,1376],{"class":206}," -",[174,1378,1304],{"class":246},[174,1380,1381],{"class":508},"          # one row is the header\n",[174,1383,1384],{"class":176,"line":220},[174,1385,224],{"emptyLinePlaceholder":223},[174,1387,1388,1390,1393,1396,1398,1401,1403,1405,1408,1411,1413],{"class":176,"line":227},[174,1389,555],{"class":206},[174,1391,1392],{"class":558}," write_split",[174,1394,1395],{"class":210},"(frame: pd.DataFrame, path: ",[174,1397,441],{"class":246},[174,1399,1400],{"class":210},", base: ",[174,1402,441],{"class":246},[174,1404,1370],{"class":206},[174,1406,1407],{"class":184}," \"data\"",[174,1409,1410],{"class":210},") -> list[",[174,1412,441],{"class":246},[174,1414,1415],{"class":210},"]:\n",[174,1417,1418,1421,1423],{"class":176,"line":253},[174,1419,1420],{"class":210},"    names ",[174,1422,243],{"class":206},[174,1424,1425],{"class":210}," []\n",[174,1427,1428,1431,1434,1436,1438,1440,1442,1444],{"class":176,"line":264},[174,1429,1430],{"class":206},"    with",[174,1432,1433],{"class":210}," pd.ExcelWriter(path, ",[174,1435,1098],{"class":239},[174,1437,243],{"class":206},[174,1439,1103],{"class":184},[174,1441,1116],{"class":210},[174,1443,398],{"class":206},[174,1445,1121],{"class":210},[174,1447,1448,1451,1454,1456,1459,1461,1464,1466,1468,1470,1472,1475,1477,1480,1483,1485,1487],{"class":176,"line":290},[174,1449,1450],{"class":206},"        for",[174,1452,1453],{"class":210}," part, start ",[174,1455,589],{"class":206},[174,1457,1458],{"class":246}," enumerate",[174,1460,658],{"class":210},[174,1462,1463],{"class":246},"range",[174,1465,658],{"class":210},[174,1467,42],{"class":246},[174,1469,475],{"class":210},[174,1471,1295],{"class":246},[174,1473,1474],{"class":210},"(frame), ",[174,1476,1367],{"class":246},[174,1478,1479],{"class":210},"), ",[174,1481,1482],{"class":239},"start",[174,1484,243],{"class":206},[174,1486,943],{"class":246},[174,1488,602],{"class":210},[174,1490,1491,1494,1496,1499,1501,1503,1506,1508,1511,1513,1516,1518],{"class":176,"line":303},[174,1492,1493],{"class":210},"            name ",[174,1495,243],{"class":206},[174,1497,1498],{"class":206}," f",[174,1500,284],{"class":184},[174,1502,432],{"class":270},[174,1504,1505],{"class":210},"base",[174,1507,670],{"class":270},[174,1509,1510],{"class":184},"_",[174,1512,432],{"class":270},[174,1514,1515],{"class":210},"part",[174,1517,670],{"class":270},[174,1519,1520],{"class":184},"\"\n",[174,1522,1523,1526,1529,1532,1535,1537,1539,1542,1544,1546,1548],{"class":176,"line":313},[174,1524,1525],{"class":210},"            frame.iloc[start:start ",[174,1527,1528],{"class":206},"+",[174,1530,1531],{"class":246}," MAX_DATA_ROWS",[174,1533,1534],{"class":210},"].to_excel(writer, ",[174,1536,1247],{"class":239},[174,1538,243],{"class":206},[174,1540,1541],{"class":210},"name, ",[174,1543,478],{"class":239},[174,1545,243],{"class":206},[174,1547,483],{"class":246},[174,1549,250],{"class":210},[174,1551,1552],{"class":176,"line":329},[174,1553,1554],{"class":210},"            names.append(name)\n",[174,1556,1557,1559],{"class":176,"line":341},[174,1558,713],{"class":206},[174,1560,1561],{"class":210}," names\n",[174,1563,1564],{"class":176,"line":351},[174,1565,224],{"emptyLinePlaceholder":223},[174,1567,1568,1571,1573,1576,1579,1581,1583,1585,1588],{"class":176,"line":368},[174,1569,1570],{"class":210},"small_demo ",[174,1572,243],{"class":206},[174,1574,1575],{"class":210}," pd.DataFrame({",[174,1577,1578],{"class":184},"\"n\"",[174,1580,438],{"class":210},[174,1582,1463],{"class":246},[174,1584,658],{"class":210},[174,1586,1587],{"class":246},"10",[174,1589,1590],{"class":210},")})\n",[174,1592,1593,1595,1597,1600],{"class":176,"line":678},[174,1594,1367],{"class":246},[174,1596,1370],{"class":206},[174,1598,1599],{"class":246}," 4",[174,1601,1602],{"class":508},"                       # tiny limit just to show the split\n",[174,1604,1605,1607,1610,1613,1616],{"class":176,"line":710},[174,1606,490],{"class":246},[174,1608,1609],{"class":210},"(write_split(small_demo, ",[174,1611,1612],{"class":184},"\"split_demo.xlsx\"",[174,1614,1615],{"class":210},"))   ",[174,1617,1618],{"class":508},"# ['data_1', 'data_2', 'data_3']\n",[174,1620,1621,1623,1625,1627,1629],{"class":176,"line":740},[174,1622,1367],{"class":246},[174,1624,1370],{"class":206},[174,1626,1373],{"class":246},[174,1628,1376],{"class":206},[174,1630,1631],{"class":246}," 1\n",[10,1633,1634,1635,1639],{},"The demonstration uses a tiny limit so the split is visible; with the real limit, the same function turns a 2.5-million-row CSV into three sheets. The underlying error when you exceed the limit by more than one row is explained in ",[14,1636,1638],{"href":1637},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-this-sheet-is-too-large-error\u002F","Fix \"This sheet is too large\" When Writing Excel with pandas",".",[20,1641,29,1646,29,1649,29,1652,29,1655,29,1661,29,1668,29,1672,29,1676,29,1680,29,1683,29,1686,29,1692,29,1697,29,1701,29,1705,29,1709,29,1711,29,1714,29,1718,29,1721,29,1724,29,1727,29,1730,29,1732,29,1735,29,1739,29,1742,29,1747,29,1751],{"viewBox":1642,"role":23,"ariaLabelledBy":1643,"xmlns":27,"style":28},"4 0 752 238",[1644,1645],"csv-size-t","csv-size-d",[31,1647,1648],{"id":1644},"What to do with a CSV of a given size",[35,1650,1651],{"id":1645},"Up to about 100,000 rows, convert directly. Up to Excel's limit of 1,048,575 data rows, convert with xlsxwriter in constant memory mode. Beyond the limit, split across sheets or deliver a summary in Excel and the full data as CSV or Parquet.",[39,1653],{"x":41,"y":42,"width":43,"height":1654,"fill":45},"238",[39,1656],{"x":1657,"y":82,"width":1658,"height":1659,"rx":52,"fill":1660,"stroke":105,"style":55},"240.0","280.0","75.5","#f0f4ff",[57,1662,1664],{"transform":1663},"translate(368.0,29.0) scale(1.000)",[61,1665],{"d":1666,"fill":64,"stroke":1667,"style":66},"M3 5h18v14H3z M3 10h18 M3 15h18 M9 5v14","var(--brand-strong,#4338ca)",[68,1669,1671],{"x":154,"y":1659,"style":1670},"font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","How many data rows?",[176,1673],{"x1":154,"y1":1674,"x2":154,"y2":1675,"stroke":105,"style":55},"91.5","111.5",[176,1677],{"x1":1678,"y1":1675,"x2":1679,"y2":1675,"stroke":105,"style":55},"134.7","625.3",[176,1681],{"x1":1678,"y1":1675,"x2":1678,"y2":1682,"stroke":105,"style":55},"157.5",[107,1684],{"points":1685,"fill":110},"134.7,161.5 129.7,152.5 139.7,152.5",[39,1687],{"x":1688,"y":1689,"width":1690,"height":1691,"rx":1587,"fill":45,"stroke":936,"style":1064},"105.9","121.5","57.5","21.0",[68,1693,1696],{"x":1678,"y":1694,"style":1695},"136.0","font-size:11.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","\u003C 100k",[39,1698],{"x":81,"y":1699,"width":1700,"height":941,"rx":52,"fill":53,"stroke":54,"style":55},"163.5","229.3",[68,1702,1704],{"x":1678,"y":1703,"style":72},"189.0","convert directly",[68,1706,1708],{"x":1678,"y":1707,"style":77},"208.5","default settings",[176,1710],{"x1":154,"y1":1675,"x2":154,"y2":1682,"stroke":105,"style":55},[107,1712],{"points":1713,"fill":110},"380.0,161.5 375.0,152.5 385.0,152.5",[39,1715],{"x":1716,"y":1689,"width":1717,"height":1691,"rx":1587,"fill":45,"stroke":936,"style":1064},"324.9","110.2",[68,1719,1720],{"x":154,"y":1694,"style":1695},"up to 1,048,575",[39,1722],{"x":1723,"y":1699,"width":1700,"height":941,"rx":52,"fill":1660,"stroke":105,"style":55},"265.3",[68,1725,1726],{"x":154,"y":1703,"style":1670},"constant_memory",[68,1728,1729],{"x":154,"y":1707,"style":77},"xlsxwriter option",[176,1731],{"x1":1679,"y1":1675,"x2":1679,"y2":1682,"stroke":105,"style":55},[107,1733],{"points":1734,"fill":110},"625.3,161.5 620.3,152.5 630.3,152.5",[39,1736],{"x":1737,"y":1689,"width":1738,"height":1691,"rx":1587,"fill":45,"stroke":936,"style":1064},"601.1","48.5",[68,1740,1741],{"x":1679,"y":1694,"style":1695},"more",[39,1743],{"x":1744,"y":1699,"width":1700,"height":941,"rx":52,"fill":1745,"stroke":1746,"style":55},"510.7","#fdefd8","var(--gold,#b4740a)",[68,1748,1750],{"x":1679,"y":1703,"style":1749},"font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","split or summarise",[68,1752,1753],{"x":1679,"y":1707,"style":77},"sheets or keep CSV",[159,1755,1757],{"id":1756},"step-6-verify-the-conversion","Step 6 — Verify the conversion",[10,1759,1760],{},"A conversion job should prove it lost nothing. Read the workbook back and compare, per source file, the row count and the total of a numeric column with the CSV it came from. It takes a second and catches every silent failure described above — a dropped last row, a mis-detected delimiter that collapsed columns, a decimal comma read as text:",[164,1762,1764],{"className":197,"code":1763,"language":199,"meta":169,"style":169},"checks = []\nworkbook = pd.read_excel(\"sales_q1.xlsx\", sheet_name=None)\nfor f in sorted(Path(\"exports\").glob(\"*.csv\")):\n    decimal = \",\" if f.name.endswith(\"_03.csv\") else \".\"\n    source = read_export(f, dtype={\"customer_id\": str}, decimal=decimal)\n    written = workbook[f.stem.replace(\"sales_\", \"\")]\n    checks.append({\n        \"file\": f.name,\n        \"rows_match\": len(source) == len(written),\n        \"amount_match\": abs(source[\"amount\"].sum() - written[\"amount\"].sum()) \u003C 0.005,\n    })\nresult = pd.DataFrame(checks)\nprint(result)\nassert result[[\"rows_match\", \"amount_match\"]].all().all()\n",[171,1765,1766,1775,1798,1818,1839,1868,1887,1892,1900,1921,1957,1962,1972,1979],{"__ignoreMap":169},[174,1767,1768,1771,1773],{"class":176,"line":177},[174,1769,1770],{"class":210},"checks ",[174,1772,243],{"class":206},[174,1774,1425],{"class":210},[174,1776,1777,1780,1782,1785,1787,1789,1791,1793,1796],{"class":176,"line":220},[174,1778,1779],{"class":210},"workbook ",[174,1781,243],{"class":206},[174,1783,1784],{"class":210}," pd.read_excel(",[174,1786,1093],{"class":184},[174,1788,475],{"class":210},[174,1790,1247],{"class":239},[174,1792,243],{"class":206},[174,1794,1795],{"class":246},"None",[174,1797,250],{"class":210},[174,1799,1800,1802,1804,1806,1808,1810,1812,1814,1816],{"class":176,"line":227},[174,1801,748],{"class":206},[174,1803,751],{"class":210},[174,1805,589],{"class":206},[174,1807,756],{"class":246},[174,1809,759],{"class":210},[174,1811,233],{"class":184},[174,1813,764],{"class":210},[174,1815,767],{"class":184},[174,1817,770],{"class":210},[174,1819,1820,1823,1825,1827,1829,1831,1833,1835,1837],{"class":176,"line":253},[174,1821,1822],{"class":210},"    decimal ",[174,1824,243],{"class":206},[174,1826,1151],{"class":184},[174,1828,1154],{"class":206},[174,1830,1157],{"class":210},[174,1832,1160],{"class":184},[174,1834,1116],{"class":210},[174,1836,1165],{"class":206},[174,1838,1168],{"class":184},[174,1840,1841,1844,1846,1848,1850,1852,1854,1856,1858,1860,1862,1864,1866],{"class":176,"line":264},[174,1842,1843],{"class":210},"    source ",[174,1845,243],{"class":206},[174,1847,781],{"class":210},[174,1849,784],{"class":239},[174,1851,243],{"class":206},[174,1853,432],{"class":210},[174,1855,435],{"class":184},[174,1857,438],{"class":210},[174,1859,441],{"class":246},[174,1861,877],{"class":210},[174,1863,880],{"class":239},[174,1865,243],{"class":206},[174,1867,1209],{"class":210},[174,1869,1870,1873,1875,1878,1880,1882,1884],{"class":176,"line":290},[174,1871,1872],{"class":210},"    written ",[174,1874,243],{"class":206},[174,1876,1877],{"class":210}," workbook[f.stem.replace(",[174,1879,1222],{"class":184},[174,1881,475],{"class":210},[174,1883,1227],{"class":184},[174,1885,1886],{"class":210},")]\n",[174,1888,1889],{"class":176,"line":303},[174,1890,1891],{"class":210},"    checks.append({\n",[174,1893,1894,1897],{"class":176,"line":313},[174,1895,1896],{"class":184},"        \"file\"",[174,1898,1899],{"class":210},": f.name,\n",[174,1901,1902,1905,1907,1909,1912,1915,1918],{"class":176,"line":329},[174,1903,1904],{"class":184},"        \"rows_match\"",[174,1906,438],{"class":210},[174,1908,1295],{"class":246},[174,1910,1911],{"class":210},"(source) ",[174,1913,1914],{"class":206},"==",[174,1916,1917],{"class":246}," len",[174,1919,1920],{"class":210},"(written),\n",[174,1922,1923,1926,1928,1931,1934,1936,1939,1941,1944,1946,1949,1952,1955],{"class":176,"line":341},[174,1924,1925],{"class":184},"        \"amount_match\"",[174,1927,438],{"class":210},[174,1929,1930],{"class":246},"abs",[174,1932,1933],{"class":210},"(source[",[174,1935,897],{"class":184},[174,1937,1938],{"class":210},"].sum() ",[174,1940,1301],{"class":206},[174,1942,1943],{"class":210}," written[",[174,1945,897],{"class":184},[174,1947,1948],{"class":210},"].sum()) ",[174,1950,1951],{"class":206},"\u003C",[174,1953,1954],{"class":246}," 0.005",[174,1956,287],{"class":210},[174,1958,1959],{"class":176,"line":351},[174,1960,1961],{"class":210},"    })\n",[174,1963,1964,1967,1969],{"class":176,"line":368},[174,1965,1966],{"class":210},"result ",[174,1968,243],{"class":206},[174,1970,1971],{"class":210}," pd.DataFrame(checks)\n",[174,1973,1974,1976],{"class":176,"line":678},[174,1975,490],{"class":246},[174,1977,1978],{"class":210},"(result)\n",[174,1980,1981,1984,1987,1990,1992,1995],{"class":176,"line":710},[174,1982,1983],{"class":206},"assert",[174,1985,1986],{"class":210}," result[[",[174,1988,1989],{"class":184},"\"rows_match\"",[174,1991,475],{"class":210},[174,1993,1994],{"class":184},"\"amount_match\"",[174,1996,1997],{"class":210},"]].all().all()\n",[10,1999,2000],{},"Keep the assertion in the scheduled version of the job: a conversion that fails loudly on a bad day is far better than one that delivers a workbook with a missing month nobody notices until the quarter closes.",[159,2002,2004],{"id":2003},"common-pitfalls","Common pitfalls",[2006,2007,2008,2016,2025,2037],"ul",{},[2009,2010,2011,2015],"li",{},[2012,2013,2014],"strong",{},"Letting Excel open the CSV instead."," Double-clicking a CSV applies Excel's own guesses; converting in Python is the only way to control types.",[2009,2017,2018,2021,2022,2024],{},[2012,2019,2020],{},"Trying Windows-1252 before UTF-8."," It decodes almost anything, so it silently garbles UTF-8 text. Try ",[171,2023,822],{}," first.",[2009,2026,2027,2030,2031,2033,2034,2036],{},[2012,2028,2029],{},"Dates as text."," Without ",[171,2032,1194],{},", dates are written as strings, which Excel cannot sort or filter as dates. Parse them, and set ",[171,2035,1108],{}," on the writer for a clean display.",[2009,2038,2039,2042,2043,475,2045,475,2047,2049,2050,2053],{},[2012,2040,2041],{},"Formulas injected from data."," A CSV value starting with ",[171,2044,243],{},[171,2046,1528],{},[171,2048,1301],{}," or ",[171,2051,2052],{},"@"," is still text when written by pandas; it only becomes a formula if someone re-imports the CSV in Excel. Converting through pandas is the safer path for untrusted exports.",[159,2055,2057],{"id":2056},"performance-and-scale-notes","Performance and scale notes",[10,2059,2060,2061,2064,2065,1639],{},"Reading a CSV is fast; writing xlsx is the slow part, because every cell becomes XML. For hundreds of thousands of rows use the xlsxwriter engine with ",[171,2062,2063],{},"engine_kwargs={\"options\": {\"constant_memory\": True}}",", which streams rows to disk instead of holding the whole sheet in memory. For millions of rows, ask whether the reader really needs them in Excel — often a summary sheet plus the full data as CSV or Parquet serves them better. The trade-offs are in ",[14,2066,2068],{"href":2067},"\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fexcel-vs-csv-vs-parquet-for-python-data-pipelines\u002F","Excel vs CSV vs Parquet for Python Data Pipelines",[159,2070,2072],{"id":2071},"conclusion","Conclusion",[10,2074,2075],{},"Convert CSVs with explicit settings: identifier columns as text, dates parsed, the encoding tried in the right order, the delimiter and decimal mark matched to the source. Combine a folder into one workbook with a sheet per file through a single writer, and respect the real sheet limit of 1,048,575 data rows — checking it yourself, because a frame of exactly 1,048,576 rows loses its last row silently with xlsxwriter.",[159,2077,2079],{"id":2078},"frequently-asked-questions","Frequently asked questions",[10,2081,2082,2085],{},[2012,2083,2084],{},"What is the simplest way to convert a CSV to Excel in Python?","\npd.read_csv(\"data.csv\").to_excel(\"data.xlsx\", index=False). The rest of this guide is about the details that one line gets wrong — encodings, delimiters, codes with leading zeros, dates, and files too big for one sheet.",[10,2087,2088,2091],{},[2012,2089,2090],{},"Why are my accented characters garbled after converting?","\nThe CSV was not saved as UTF-8 — Excel on Windows often writes Windows-1252. Pass the right encoding to read_csv, or try \"utf-8-sig\" first and fall back to \"cp1252\".",[10,2093,2094,2097],{},[2012,2095,2096],{},"How many rows can one Excel sheet hold?","\n1,048,576 rows including the header row, so at most 1,048,575 data rows under a header. Larger files must be split across sheets or kept in another format.",[10,2099,2100,2103],{},[2012,2101,2102],{},"Why did my ZIP codes lose their leading zeros?","\nread_csv inferred the column as numbers. Read identifier columns as text with dtype={\"zip\": str} so 01234 stays 01234.",[159,2105,2107],{"id":2106},"related","Related",[2006,2109,2110,2116,2123,2130],{},[2009,2111,2112,2113,2115],{},"Up one level: ",[14,2114,17],{"href":16}," — every format in and out.",[2009,2117,2118,2122],{},[14,2119,2121],{"href":2120},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Fconvert-excel-to-csv-with-python\u002F","Convert Excel to CSV with Python"," — the reverse direction.",[2009,2124,2125,2129],{},[14,2126,2128],{"href":2127},"\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fkeep-leading-zeros-when-reading-excel-with-pandas\u002F","Keep Leading Zeros When Reading Excel with pandas"," — the same problem on the Excel side.",[2009,2131,2132,2136],{},[14,2133,2135],{"href":2134},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Fwrite-large-dataframes-to-excel-with-write-only-mode\u002F","Write Large DataFrames to Excel with write_only Mode"," — memory-friendly writing.",[2138,2139,2140],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}",{"title":169,"searchDepth":220,"depth":220,"links":2142},[2143,2144,2145,2146,2147,2148,2149,2150,2151,2152,2153,2154],{"id":161,"depth":220,"text":162},{"id":379,"depth":220,"text":380},{"id":530,"depth":220,"text":531},{"id":826,"depth":220,"text":827},{"id":1073,"depth":220,"text":1074},{"id":1349,"depth":220,"text":1350},{"id":1756,"depth":220,"text":1757},{"id":2003,"depth":220,"text":2004},{"id":2056,"depth":220,"text":2057},{"id":2071,"depth":220,"text":2072},{"id":2078,"depth":220,"text":2079},{"id":2106,"depth":220,"text":2107},"2026-09-23","Turn CSV exports into proper Excel workbooks — detect the encoding and delimiter, keep IDs as text, parse dates, combine many CSVs into one workbook with a sheet each, split files larger than Excel's row limit, and format the result.","md",[2159,2161,2163,2165],{"q":2084,"a":2160},"pd.read_csv(\"data.csv\").to_excel(\"data.xlsx\", index=False). The rest of this guide is about the details that one line gets wrong — encodings, delimiters, codes with leading zeros, dates, and files too big for one sheet.",{"q":2090,"a":2162},"The CSV was not saved as UTF-8 — Excel on Windows often writes Windows-1252. Pass the right encoding to read_csv, or try \"utf-8-sig\" first and fall back to \"cp1252\".",{"q":2096,"a":2164},"1,048,576 rows including the header row, so at most 1,048,575 data rows under a header. Larger files must be split across sheets or kept in another format.",{"q":2102,"a":2166},"read_csv inferred the column as numbers. Read identifier columns as text with dtype={\"zip\": str} so 01234 stays 01234.","convert csv to xlsx in python",null,{"breadcrumb":2170},[2171,2174,2177],{"name":2172,"item":2173},"Home","\u002F",{"name":2175,"item":2176},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":17,"item":16},"\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-csv-files-to-excel-with-python",{"title":2180,"description":2181},"Convert CSV to Excel (XLSX) with Python and pandas","Convert one or many CSV files to Excel with pandas — encodings, semicolon delimiters, leading zeros, dates, one sheet per CSV, splitting past 1,048,576 rows without losing the last row, and formatting.","convert-csv-files-to-excel-with-python","getting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-csv-files-to-excel-with-python\u002Findex",[2185,2186,2187],"file-formats","writing-excel","pandas","how-to","TnTQ6QJP1HWINeup3Lv7-iV6kHDAMrinTmil85LWjwk",[2191,2195],{"title":2192,"path":2193,"stem":2194,"children":-1},"Convert an Excel Sheet to JSON with Python","\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-an-excel-sheet-to-json-with-python","getting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-an-excel-sheet-to-json-with-python\u002Findex",{"title":2196,"path":2197,"stem":2198,"children":-1},"Convert Excel Sheets to YAML or TOML Config","\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-excel-sheets-to-yaml-or-toml-config","getting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fconvert-excel-sheets-to-yaml-or-toml-config\u002Findex",[2200,2202],{"path":2201,"title":17},"\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions",{"path":2203,"title":2175},"\u002Fgetting-started-with-python-excel-automation",[],[2206,2209,2211,2214,2217,2221],{"path":2207,"title":2208,"kind":2188},"\u002Fadvanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Fconvert-excel-files-to-parquet-with-python","Convert Excel Files to Parquet with Python",{"path":2210,"title":2121,"kind":2188},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Fconvert-excel-to-csv-with-python",{"path":2212,"title":2068,"kind":2213},"\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fexcel-vs-csv-vs-parquet-for-python-data-pipelines","compare",{"path":2215,"title":2216,"kind":2213},"\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fpick-an-excel-engine-for-xlsx-xlsm-xls-xlsb-and-ods","Pick an Excel Engine for .xlsx, .xlsm, .xls, .xlsb and .ods",{"path":2218,"title":2219,"kind":2220},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Ffix-garbled-characters-in-excel-data","Fix Garbled Characters Like \"CafÃ©\" and \"â€™\" in Excel Data","fix",{"path":2222,"title":2223,"kind":2188},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fextract-vba-macro-code-from-an-excel-file","Extract VBA Macro Code from an Excel File",1790972059113]