10
votes

Comment lire une feuille de calcul Excel en C # rapidement

J'utilise microsoft.office.interop.excel pour lire une feuille de calcul ouverte en mémoire.

gXlWs = (Microsoft.Office.Interop.Excel.Worksheet)gXlApp.ActiveWorkbook.ActiveSheet;
int NumCols = 7;
string[] Fields = new string[NumCols];
string input = null;
int NumRow = 2;
while (Convert.ToString(((Microsoft.Office.Interop.Excel.Range)gXlWs.Cells[NumRow, 1]).Value2) != null)
{
    for (int c = 1; c <= NumCols; c++)
    {
        Fields[c-1] = Convert.ToString(((Microsoft.Office.Interop.Excel.Range)gXlWs.Cells[NumRow, c]).Value2);
    }
    NumRow++;

    //Do my other processing
}


2 commentaires

Savez-vous si vous êtes io lié ou cpu lié? Vous pouvez probablement paralleraliser ce code sur une machine multi-noyau / cpu.


Vous pouvez également faire une demande SQL sur une feuille de calcul Excel à l'aide de Ado.net. De cette façon, vous pouvez éviter de faire la boucle de temps. Voir Stackoverflow.com/questions/6789648/...


6 Réponses :


4
votes

Il existe plusieurs options - toutes impliquent une bibliothèque supplémentaire:

  • OpenXML 2.0 (bibliothèque libre de MS ) Peut être utilisé pour lire / modifier le contenu d'un fichier .xlsx afin de pouvoir le faire avec ce que vous voulez

  • Certaines bibliothèques 3RD-Parties sont livrées avec des contrôles de réseau vous permettant de faire beaucoup plus encore avec des fichiers Excel de votre application (IT WinForms / WPF / ASP.NET ...) comme tableur
    , aspossible.cells etc.


4 commentaires

Mais est-ce qu'il est probable d'être plus rapide?


Oui, c'est pourquoi je l'ai proposé, il accède au fichier sans utiliser Excel et sans les frais généraux de COM / Interop


Mais je veux accéder à une feuille de calcul ouverte en mémoire. Pour que je puisse le changer de manière interactive puis exécuter mon code à nouveau. Je pense que ce que vous suggère de lire le fichier sauvegardé de disque - ou je me trompe?


@Maninmoon - Vous devrez alors accepter que la lecture du fichier ouvert en mémoire va avoir des problèmes de performance. Vous n'avez pas indiqué combien de temps il faut pour lire 180 000 enregistrements.



0
votes

Je suppose que ce n'est pas la source de "ralentissement" ...

En réalité, la récupération des valeurs de cellules est très lente.

Je pense que cette conversion n'est pas nécessaire: < Pré> xxx

Ça devrait fonctionner sans cela.

et vous pouvez demander directement: xxx

Essayez de déplacer toute la plage Ou, au moins, la ligne entière à une matrice d'objet et travaille avec elle au lieu de la gamme elle-même.


5 commentaires

Pendant que vous faites de bons points, rien de tout cela augmenterait la vitesse de son code. La conversion ne ralentit pas son code.


Louerait toute la gamme dans (une matrice de 180 000,7) être plus rapide? J'ai vu une référence à cela avec .get_range mais je ne suis pas sûr de la façon dont vous l'utiliseriez - des indices seraient formidables.


@Maninmoon - Ce ne serait pas plus rapide, cela aurait plus de sens, vous allez toujours être limité par la façon dont vous lisez le fichier.


Cela pourrait être plus rapide. S'il y a des frais généraux à chaque "lecture" du classeur ouvert. Je ne sais tout simplement pas comment l'utiliser.


Eh bien, la solution que vous avez montrée ci-dessus semble être ce que j'ai suggéré. Êtes-vous d'accord?



1
votes

Je ne suis pas sûr que "Convertir" est efficace. Y a-t-il de toute façon je pourrais faire ce plus rapide?

Qu'est-ce qui vous fait croire cela? Je vous promets que convert.tostring () est la méthode la plus efficace dans le code que vous avez affiché. Votre problème est que votre boucle à travers 180 000 enregistrements dans un document Excel ...

Vous pourriez diviser l'opération depuis que vous connaissez le nombre de lignes c'est un trival à faire.

Pourquoi couvrez-vous la valeur2 à une chaîne exactement?


2 commentaires

@Maninmoon - Expliquez ce que vous entendez par cette déclaration. Vous comprenez que votre chaîne [] ne peut que 7 cordes juste? Votre code n'a donc pas beaucoup de sens si votre lecture de 180 000 enregistrements.


Où j'ai mis "// faire mon autre procèses" je traite avec chaque "rangée" séparément



28
votes

Bonjour, j'ai trouvé un moyen très plus rapide.

Il est préférable de lire les données complètes en une fois à l'aide de "get_range". Ceci charge les données en mémoire et je peux boucler à travers cela comme un tableau normal. P>

Microsoft.Office.Interop.Excel.Range range = gXlWs.get_Range("A1", "F188000");
object[,] values = (object[,])range.Value2;
int NumRow=1;
while (NumRow < values.GetLength(0))
{
    for (int c = 1; c <= NumCols; c++)
    {
        Fields[c - 1] = Convert.ToString(values[NumRow, c]);
    }
    NumRow++;
}


7 commentaires

Qu'est-ce que Numrow ++ signifie?


Numrow ++ est identique à numrow = numrow + 1;


Vous avez utilisé "F188000". Dans mon cas, je ne sais pas combien de rangées seraient là. Que dois-je faire?


Vous pouvez accélérer la conversion à l'aide de array.copy () . Voir Stackoverflow.com/a/5083690/380384 . Bien sûr, cela dépend de ce que sont les contenus cellulaires. Sont-ils des chiffres ou des cordes?


Notez que le tableau 2-D résultant est (bizarrement) 1 à base de 1 à 0, malgré le fait qu'il ressemble à une matrice C # standard. Mais oui, c'est des ordres de grandeur plus rapidement que d'itération à travers les cellules sous-jacentes - merci.


Absolument fantastique ... sérieusement, le code qui a pris des minutes est fait en un clin d'œil.


@ user728630 Une autre méthode d'obtention de la plage de données est la suivante: Excel.excel.Range Datarange = Excelworksheet.ReçuRange; objet [] ExcelRangeValues ​​= (objet []) Datarange.value2; var rowcount = datarange.rows.count + 1; var colonnecount = Datarange.columns.Count + 1;



0
votes

Utilisez la méthode OLEDB . C'est le plus rapide comme suit; xxx


0 commentaires

0
votes

J'ai trouvé un moyen vraiment rapide de lire Excel de ma manière spécifique. J'ai besoin de l'obtenir comme une éventail de chaîne en deux dimensions. Avec vraiment grand Excel, il a fallu environ une heure de vieille. De cette façon, je reçois mes valeurs en 20sec.

J'utilise cette nugget: https://reposhub.com/dotnet/office/exceldatareader-exceldatareader-exceldatareader.html

et voici mon code: xxx


0 commentaires