CSV Import on Android: Where Data Loading Breaks
CSV import on Android breaks not at the "Upload" button, but at the data.
The file comes from 1C, Google Sheets, or a CRM export — and it almost always contains discrepancies: a ; delimiter instead of ,, Windows-1251 encoding instead of UTF-8, a decimal comma in numbers, dates in dd.mm.yyyy format alongside ISO.
Naive CSV parsing by comma on such files causes column shifting: one row with an extra quote — and all subsequent fields slide into neighboring columns.
A separate category of failures is large files. An export of 50-100 thousand rows, read entirely into memory, crashes the app on devices with 2-3 GB of RAM: the system kills the process before the user sees progress.
A connection drop mid-upload makes things worse — a repeated import creates duplicates because the first attempt partially wrote the data.
Excel adds its own pitfalls: .xlsx is a ZIP archive with XML inside, and trying to open it as a text CSV yields garbage instead of a table. And formulas, merged cells, and multiple sheets require an explicit decision — which sheet to read and what to do with calculated values.
Finally, CSV import errors are almost never shown to the user clearly: "failed to upload file" doesn't say which row has the broken quote.
Without a row-by-row report with the row number and the rejection reason, a person edits the file blindly, and support gets tickets with no diagnostics.
Let's break down how each of these failures is addressed at the level of the loading and parsing architecture.
What managed data import in an app delivers
Managed import is not a "upload file button" but a pipeline: structure parsing, row validation, error reporting, and transactional writing.
Once it is built, data import speed stops depending on file size: streaming processing maintains a steady pace across tens of thousands of rows, and progress is visible to the user instead of freezing on a single screen.
Import reliability delivers predictability: each row either passes in full or is rejected with a clear reason — no partially written records that later have to be cleaned up manually.
The share of successful imports grows thanks to pre-validation of format, encoding, and required fields before writing to the database.
Reduced manual input is a direct effect of mapping file columns to app fields. The user confirms the mapping once, then the system remembers the template and applies it to subsequent exports. This eliminates retyping and the typos that come with it.
Support requests drop when the error is explained on the spot: instead of "import failed," the user sees the row number, the problematic field, and a hint.
We work on Android and iOS taking into account each platform's constraints — file access, background processing, behavior when the app is minimized.
What we measure at the output
- File processing time on a reference set of rows — before and after optimization.
- Share of imports completed without manual corrections.
- Number of requests on the topic of data upload over a period.
- Completeness of the error report: how many rejected rows received a clear reason.
We capture these metrics on the customer's pilot dataset, not on synthetic data — that way the real file profile and bottlenecks become visible.
Methods of Loading CSV and Excel: Comparison of Approaches
The choice of import method determines how the application will behave with a 200,000-row file and on a phone with 300 MB of free memory.
Below are four working options that are realistically chosen between during design: they differ in data source, memory requirements, and resilience to connection drops.
| Option | When it fits | Limitations |
|---|---|---|
| Import from file (local selection) | One-time uploads, offline work, data comes from the user | Requires access to storage; large files require streaming processing |
| Loading from cloud | Data resides in shared storage, synchronization between devices is needed | Depends on the network, requires authorization and handling of expired tokens |
| Streaming import | Files of tens of thousands of rows, limited memory | More complex to implement: line-by-line reading, without loading the entire file into memory |
| Background synchronization | Regular exchange, data is updated without user involvement | Requires a scheduler, retries, and OS permissions for background work |
What Matters When Choosing
Streaming import reads the file line by line and writes to the database in batches — the application does not hold the entire dataset in memory, so a 200,000-row file passes without crashes.
Local import from a file provides independence from the network but requires correct handling of permissions and external storage.
Cloud loading and background synchronization solve the task of regular exchange but add requirements for network and authorization. In practice, they are combined: streaming reading as the foundation, background synchronization as a layer on top for recurring scenarios.
How we structure CSV import in Android: project stages
CSV import in Android almost never comes down to "read the file and lay it out by fields." Sources come from 1C, CRM exports, accounting spreadsheets — with different delimiters, encodings, decimal commas, and "headers" on the third row.
That is why we run the project in stages: each next one relies on a fixed result of the previous one, rather than on guesses about "how things actually are at the client's side."
Implementation stages of import
- Data audit. We collect real exports over several periods, not just one sample. We record delimiters, encodings, date and number formats, empty rows, duplicate headers. The output is a list of sources and their differences.
- Column mapping schema. We match the file fields to the application fields: what is mandatory, what is optional, where transformations are needed. We describe mapping rules declaratively — a new column is added by editing the configuration, not by rebuilding the logic.
- Parser and validation implementation. Streaming reads instead of loading the entire file into memory, type and range checks on every row. Errors are collected into a report with the row number and reason, rather than crashing the entire import.
- Conflict handling. We define the behavior when keys match: update, skip, create a duplicate. We fix this decision before development — later it costs the most.
- Testing the import on real files. We run exports from all sources, including "dirty" ones: broken encodings, extra columns, truncated rows. We verify the count and content of records before and after.
- Handover and documentation. We provide the description of formats, mapping rules, and error behavior — so that support can be run without us.
The order of the stages is not accidental: the audit and mapping remove most of the risks, while testing on real files catches what cannot be reproduced on synthetic data. Describe your sources — we will get back to you with an estimate and a work plan.
Artifacts and documentation after import implementation
After the project is delivered, you are left not with a "black box" but with a complete set that allows the import module to be developed further, handed over to another team, and maintained without us.
Everything we design during the work is captured in artifacts — from configurations to instructions for your employees.
- Import module in the codebase — an isolated component with extension points: adding a new format or field does not require rewriting the parsing logic.
- Mapping schemas — a description of how file columns correspond to application fields, including type conversion rules, default values, and handling of optional columns.
- Validation rules — a list of checks at the row and file level: required fields, ranges, duplicates, broken encodings. With an indication of which error blocks the import and which merely flags the record.
- Import documentation — how parsing works, where intermediate data is stored, how to read the error log, and by what signs to distinguish a format failure from a data failure.
- User guide — a step-by-step scenario for an employee: which file to prepare, what restrictions on size and structure apply, and what to do in case of a partially successful import.
- Update procedure — the sequence of actions when the file structure or application fields change: who edits the mapping schema, and how compatibility with old exports is verified.
- Set of test data — reference files with valid and intentionally corrupted rows, so that regressions are caught before release to production.
Separately, we hand over a decision log: why this particular parsing strategy was chosen, what file size restrictions apply and why, and where the bottlenecks are as volumes grow.
This eliminates the main support problem — when six months later no one remembers why a validation rule is formulated exactly the way it is.
The set is designed on the assumption that from here on you work independently or with any other team. If an extension is needed, we will discuss the task and come back with an estimate and a plan.
Case study: speeding up price list import in a mobile app
The client — a distributor of building materials — came with a classic pain point: managers exported a price list from the ERP system into a CSV of 40-60 thousand rows and uploaded it to the mobile app right "in the field." The import ran as a line-by-line parse on the device, with no preliminary validation, and on an average smartphone took 6-8 minutes.
The app froze, some sessions dropped on timeout, and if the file contained an extra comma in a product name, the parse silently broke halfway through.
We broke down the bottleneck: the client parsed the entire file into memory and synchronously wrote each row to the local database.
We rewrote the pipeline — streaming CSV parsing with batched writes in transactions of 500 rows, preliminary validation of the schema and types on the first rows, and heavy files go to server-side processing with a ready-made dataset returned.
Errors are now collected into a report by row numbers, and the manager sees exactly what failed instead of a blank screen.
Metrics before and after
| Metric | Before | After |
|---|---|---|
| Price list import time for 50 thousand rows | 6-8 minutes | 20-40 seconds |
| Share of successful imports on the first try | ~70% | 98% |
| Support requests about uploads | 30-40 per month | isolated cases |
We also separately handled rollback: before writing, a snapshot of the current catalog is created, so a failed import doesn't leave the app in a half-broken state — the manager returns to the previous version of the price list with one button.
We built a similar pipeline for a field request service on Android: there, importing Excel exports was cut from minutes to seconds with the same data volume.
How is CSV import different from Excel import on Android?
CSV is a flat text format: rows separated by line breaks, and columns separated by a single delimiter character (comma, semicolon, tab).
It has no structure other than the order of columns, so parsing on Android boils down to correctly handling delimiters, quotes, and escaping: a value with a comma inside must be in quotes, otherwise the row will "fall apart" into extra columns.
A separate headache is encoding: files from old exports come in single-byte encodings, and without explicit detection the header and Cyrillic text turn into garbage. We detect the encoding from the first bytes and fall back to manual selection if the automation is not confident.
Excel is no longer text but a container: a workbook, sheets, cell types, formulas, merged cells, styles. A cell value can be computed, and when reading you need to decide whether to take the saved formula result or recalculate it.
Merged cells break the tabular grid: the value is stored only in the top-left cell, while the rest are empty, and when parsing this looks like missing data. The parser must "stretch" the value across the entire merge range, otherwise the rows will shift. Plus multiple sheets and hidden rows — you need to agree in advance on what exactly counts as data.
The practical takeaway: CSV is cheaper and more predictable to parse, but poor in structure and types — everything comes in as strings, and converting to numbers and dates falls on the application.
Excel is richer, but requires full workbook reading and explicit rules for formulas, merges, and sheets. A reliable solution is a single import layer that brings both formats into one internal table, and then validates rows the same way.
This way the user can upload both csv and excel, while the validation and error logic remains shared.
Common technical concerns about data import
Importing CSV and Excel in a mobile app almost never comes down to "read the file and write the rows." The main difficulties start with volume: a file with tens of thousands of rows cannot be held entirely in memory — on a weak device the process gets killed by the system.
That is why the stream is read line by line, buffered, and written in batches to the local database within a transaction, while progress is shown to the user. This way the import survives both the app being minimized and a lack of memory.
A separate topic is unstable networks and duplicates. Synchronization runs in idempotent packets with a record key: resending after a drop does not create copies, and conflicts are resolved by the "last change wins" rule or by source priority.
Security is covered at the level of file access, local storage encryption, and validation of every row before writing — corrupted and foreign data is filtered out at the input, not afterward.
What happens if the user closes the app during import?
The import is split into short transactions with position saving. On the next launch, the process continues from the last successfully written row rather than starting over — already loaded data is not duplicated.
How does the app tell a duplicate from a new record?
By a composite key: for example, an external identifier plus the source. If a record with such a key already exists, it is updated rather than added a second time. This makes re-importing the same file safe.
The file arrives in the wrong encoding or with a different delimiter — will the import fail?
No. The encoding and delimiter are detected automatically, and rows with a mismatched number of columns go into an error report with the row number, without interrupting the loading of the rest.
Can you restrict which data the user can import at all?
Yes. Permissions are checked before reading the file, and the column schema is validated against a template — extra fields are ignored, required ones are checked for being filled in. This way a foreign or corrupted file will not get into the database.
Let's discuss your CSV import task for Android
Importing CSV into Android almost never boils down to "read the file and split it into columns." The questions start with the data source: the file comes from a 1C export, Google Sheets, an old database, or an operator prepares it manually.
This determines the encoding, the delimiter, the date format, and how much dirty data will have to be cleaned up on input.
To come back with an import estimate and a work plan rather than generalities, we need to understand the structure of your scenario. Describe the task — and we'll analyze it concretely.
What's worth clarifying at the start:
- Where the file comes from: manual upload by the user, download via a link, or synchronization with an external system.
- Volume and frequency: a one-time import of a few thousand rows or regular ingestion of large exports.
- Data structure: how many columns, whether there are nested reference lists, required fields, relationships between tables.
- What to do with erroneous rows: reject the entire file, skip broken records, or show a report with row numbers.
- Where the data ends up: a local database on the device, a server, or cloud storage, and whether reverse export is needed.
- Access requirements: which users have the right to upload and modify data.
It's useful to prepare a sample of a real file in advance — with the same columns, encoding, and "dirty" rows as in production.
One such example removes half the questions and makes the estimate accurate: we see the delimiters, date formats, duplicates, and decide where validation is needed and where normalization is.
Next, we'll come back with an estimate and a work plan: stages, timelines, what we do on the app side and what on the server side, and how we'll test the import on your data before release.
Describe the task in whatever format is convenient — messaging, a call, or a short description with a sample file.







