Utilisation D'Excel OleDb pour obtenir des noms de feuille dans L'ordre de feuille
j'utilise OleDb pour lire à partir d'un classeur excel avec de nombreuses feuilles.
je dois lire les noms des feuilles, mais j'ai besoin d'eux dans l'ordre où ils sont définis dans la feuille de calcul; donc si j'ai un fichier qui ressemble à ceci;
|_____|_____|____|____|____|____|____|____|____|
|_____|_____|____|____|____|____|____|____|____|
|_____|_____|____|____|____|____|____|____|____|
__GERMANY__/__UK__/__IRELAND__/
alors je dois obtenir le dictionnaire
1="GERMANY",
2="UK",
3="IRELAND"
j'ai essayé d'utiliser OleDbConnection.GetOleDbSchemaTable()
, et ça me donne la liste des noms, mais ça les trie par ordre alphabétique. L'Alpha-sorte signifie que je ne savoir à quel numéro de feuille correspond un nom particulier.
GERMANY, IRELAND, UK
qui a changé l'ordre de UK
et IRELAND
.
la raison pour laquelle j'ai besoin qu'il soit trié est que je dois laisser l'utilisateur choisir une gamme de données par nom ou index; ils peuvent demander "toutes les données de L'Allemagne à L'Irlande" ou "données de la feuille 1 à la feuille 3".
Toutes les idées seraient grandement appréciés.
si je pourrait utiliser les classes bureau interop, ce serait simple. Malheureusement, je ne peux pas parce que les classes interop ne fonctionnent pas de manière fiable dans des environnements non interactifs tels que les Services windows et ASP.NET sites, donc j'avais besoin d'utiliser OLEDB.
11 réponses
ne peut pas trouver cela dans la documentation MSDN réelle, mais un modérateur dans les forums dit
je crains que OLDB ne préserve pas l'ordre des feuilles comme ils étaient dans Excel
Feuille Excel des Noms de Feuille de Commande
semble comme ceci serait une exigence assez commune qu'il y aurait un contournement de travail décent.
ne pouvez-vous pas simplement boucler les feuilles de 0 à compte des noms -1? de cette façon, vous devriez le faire dans le bon ordre.
Modifier
j'ai remarqué à travers les commentaires qu'il y a beaucoup de préoccupations au sujet de l'utilisation des classes Interop pour récupérer les noms des feuilles. Voici donc un exemple d'utilisation D'OLEDB pour les récupérer:
/// <summary>
/// This method retrieves the excel sheet names from
/// an excel workbook.
/// </summary>
/// <param name="excelFile">The excel file.</param>
/// <returns>String[]</returns>
private String[] GetExcelSheetNames(string excelFile)
{
OleDbConnection objConn = null;
System.Data.DataTable dt = null;
try
{
// Connection String. Change the excel file to the file you
// will search.
String connString = "Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data Source=" + excelFile + ";Extended Properties=Excel 8.0;";
// Create connection object by using the preceding connection string.
objConn = new OleDbConnection(connString);
// Open connection with the database.
objConn.Open();
// Get the data table containg the schema guid.
dt = objConn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
if(dt == null)
{
return null;
}
String[] excelSheets = new String[dt.Rows.Count];
int i = 0;
// Add the sheet name to the string array.
foreach(DataRow row in dt.Rows)
{
excelSheets[i] = row["TABLE_NAME"].ToString();
i++;
}
// Loop through all of the sheets if you want too...
for(int j=0; j < excelSheets.Length; j++)
{
// Query each excel sheet.
}
return excelSheets;
}
catch(Exception ex)
{
return null;
}
finally
{
// Clean up.
if(objConn != null)
{
objConn.Close();
objConn.Dispose();
}
if(dt != null)
{
dt.Dispose();
}
}
}
extrait de Article sur le CodeProject.
puisque le code ci-dessus ne couvre pas les procédures pour extraire le nom de la liste de la feuille pour Excel 2007, le code suivant sera applicable pour Excel (97-2003) et Excel 2007 aussi:
public List<string> ListSheetInExcel(string filePath)
{
OleDbConnectionStringBuilder sbConnection = new OleDbConnectionStringBuilder();
String strExtendedProperties = String.Empty;
sbConnection.DataSource = filePath;
if (Path.GetExtension(filePath).Equals(".xls"))//for 97-03 Excel file
{
sbConnection.Provider = "Microsoft.Jet.OLEDB.4.0";
strExtendedProperties = "Excel 8.0;HDR=Yes;IMEX=1";//HDR=ColumnHeader,IMEX=InterMixed
}
else if (Path.GetExtension(filePath).Equals(".xlsx")) //for 2007 Excel file
{
sbConnection.Provider = "Microsoft.ACE.OLEDB.12.0";
strExtendedProperties = "Excel 12.0;HDR=Yes;IMEX=1";
}
sbConnection.Add("Extended Properties",strExtendedProperties);
List<string> listSheet = new List<string>();
using (OleDbConnection conn = new OleDbConnection(sbConnection.ToString()))
{
conn.Open();
DataTable dtSheet = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
foreach (DataRow drSheet in dtSheet.Rows)
{
if (drSheet["TABLE_NAME"].ToString().Contains("$"))//checks whether row contains '_xlnm#_FilterDatabase' or sheet name(i.e. sheet name always ends with $ sign)
{
listSheet.Add(drSheet["TABLE_NAME"].ToString());
}
}
}
return listSheet;
}
ci-dessus la fonction retourne la liste de la feuille en particulier le fichier excel pour les deux types d'excel(97,2003,2007).
une autre voie:
un fichier xls(x) n'est qu'une collection de *.fichiers xml stockés dans un *.conteneur zip. décompressez le fichier "app.xml" dans le dossier docProps.
<?xml version="1.0" encoding="UTF-8" standalone="true"?>
-<Properties xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes" xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties">
<TotalTime>0</TotalTime>
<Application>Microsoft Excel</Application>
<DocSecurity>0</DocSecurity>
<ScaleCrop>false</ScaleCrop>
-<HeadingPairs>
-<vt:vector baseType="variant" size="2">
-<vt:variant>
<vt:lpstr>Arbeitsblätter</vt:lpstr>
</vt:variant>
-<vt:variant>
<vt:i4>4</vt:i4>
</vt:variant>
</vt:vector>
</HeadingPairs>
-<TitlesOfParts>
-<vt:vector baseType="lpstr" size="4">
<vt:lpstr>Tabelle3</vt:lpstr>
<vt:lpstr>Tabelle4</vt:lpstr>
<vt:lpstr>Tabelle1</vt:lpstr>
<vt:lpstr>Tabelle2</vt:lpstr>
</vt:vector>
</TitlesOfParts>
<Company/>
<LinksUpToDate>false</LinksUpToDate>
<SharedDoc>false</SharedDoc>
<HyperlinksChanged>false</HyperlinksChanged>
<AppVersion>14.0300</AppVersion>
</Properties>
le fichier est un fichier Allemand (Arbeitsblätter = worksheets). Les noms de table (Tabelle3 etc) sont dans le bon ordre. Vous avez juste besoin de lire ces balises;)
concerne
j'ai créé la fonction ci-dessous en utilisant les informations fournies dans la réponse de @kraeppy ( https://stackoverflow.com/a/19930386/2617732 ). Cela nécessite le .net framework v4.5 à utiliser et nécessite une référence au système.IO.Compression. Cela ne fonctionne que pour les fichiers xlsx et pas pour les anciens fichiers xls.
using System.IO.Compression;
using System.Xml;
using System.Xml.Linq;
static IEnumerable<string> GetWorksheetNamesOrdered(string fileName)
{
//open the excel file
using (FileStream data = new FileStream(fileName, FileMode.Open))
{
//unzip
ZipArchive archive = new ZipArchive(data);
//select the correct file from the archive
ZipArchiveEntry appxmlFile = archive.Entries.SingleOrDefault(e => e.FullName == "docProps/app.xml");
//read the xml
XDocument xdoc = XDocument.Load(appxmlFile.Open());
//find the titles element
XElement titlesElement = xdoc.Descendants().Where(e => e.Name.LocalName == "TitlesOfParts").Single();
//extract the worksheet names
return titlesElement
.Elements().Where(e => e.Name.LocalName == "vector").Single()
.Elements().Where(e => e.Name.LocalName == "lpstr")
.Select(e => e.Value);
}
}
C'est court, rapide, sûr, et utilisable...
public static List<string> ToExcelsSheetList(string exceladdress)
{
List<string> sheets = new List<string>();
using (OleDbConnection connection = new OleDbConnection((exceladdress.TrimEnd().ToLower().EndsWith("x")) ? "Provider=Microsoft.ACE.OLEDB.12.0;Data Source='" + exceladdress + "';" + "Extended Properties='Excel 12.0 Xml;HDR=YES;'"
: "provider=Microsoft.Jet.OLEDB.4.0;Data Source='" + exceladdress + "';Extended Properties=Excel 8.0;"))
{
connection.Open();
DataTable dt = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
foreach (DataRow drSheet in dt.Rows)
if (drSheet["TABLE_NAME"].ToString().Contains("$"))
{
string s = drSheet["TABLE_NAME"].ToString();
sheets.Add(s.StartsWith("'")?s.Substring(1, s.Length - 3): s.Substring(0, s.Length - 1));
}
connection.Close();
}
return sheets;
}
j'aime l'idée de @deathApril de nommer les feuilles comme 1_Germany, 2_UK, 3_IRELAND. J'ai aussi eu votre problème, pour ce faire renommer des centaines de feuilles. Si vous n'avez pas de problème pour renommer le nom de la feuille, alors vous pouvez utiliser cette macro pour le faire pour vous. Cela prendra moins de secondes pour renommer tous les noms de feuille. malheureusement ODBC, OLEDB retourner l'ordre de nom de feuille par asc. Il n'y a pas de remplacement. Vous devez utiliser COM ou renommer votre nom dans l'ordre.
Sub Macro1()
'
' Macro1 Macro
'
'
Dim i As Integer
For i = 1 To Sheets.Count
Dim prefix As String
prefix = i
If Len(prefix) < 4 Then
prefix = "000"
ElseIf Len(prefix) < 3 Then
prefix = "00"
ElseIf Len(prefix) < 2 Then
prefix = "0"
End If
Dim sheetName As String
sheetName = Sheets(i).Name
Dim names
names = Split(sheetName, "-")
If (UBound(names) > 0) And IsNumeric(names(0)) Then
'do nothing
Else
Sheets(i).Name = prefix & i & "-" & Sheets(i).Name
End If
Next
End Sub
mise à jour: Après avoir lu @SidHoland commentaire concernant BIFF une idée flashé. Les étapes suivantes peuvent être effectuées par code. Je ne sais pas si vous voulez vraiment faire cela pour obtenir les noms de feuille dans le même ordre. Faites-moi savoir si vous avez besoin d'aide pour le faire à travers le code.
1. Consider XLSX as a zip file. Rename *.xlsx into *.zip
2. Unzip
3. Go to unzipped folder root and open /docprops/app.xml
4. This xml contains the sheet name in the same order of what you see.
5. Parse the xml and get the sheet names
mise à jour: Une autre solution-NPOI pourrait être utile ici http://npoi.codeplex.com /
FileStream file = new FileStream(@"yourexcelfilename", FileMode.Open, FileAccess.Read);
HSSFWorkbook hssfworkbook = new HSSFWorkbook(file);
for (int i = 0; i < hssfworkbook.NumberOfSheets; i++)
{
Console.WriteLine(hssfworkbook.GetSheetName(i));
}
file.Close();
cette solution fonctionne pour xls. Je n'ai pas essayer xlsx.
Merci,
Esen
ça a marché pour moi. Volée à partir d'ici: Comment obtenez-vous le nom de la première page d'un classeur excel?
object opt = System.Reflection.Missing.Value;
Excel.Application app = new Microsoft.Office.Interop.Excel.Application();
Excel.Workbook workbook = app.Workbooks.Open(WorkBookToOpen,
opt, opt, opt, opt, opt, opt, opt,
opt, opt, opt, opt, opt, opt, opt);
Excel.Worksheet worksheet = workbook.Worksheets[1] as Microsoft.Office.Interop.Excel.Worksheet;
string firstSheetName = worksheet.Name;
selon MSDN, dans un cas de tableurs à L'intérieur D'Excel, cela pourrait ne pas fonctionner parce que les fichiers Excel ne sont pas de vraies bases de données. Donc, vous ne serez pas en mesure d'obtenir les fiches de nom dans l'ordre de leur visualisation dans le classeur.
Code pour obtenir le nom des feuilles selon leur apparence visuelle en utilisant interop:
ajouter une référence à la bibliothèque D'objets Microsoft Excel 12.0.
code suivant donnera le nom des feuilles dans l'ordre réel stocké dans le classeur, pas triées nom.
Code Échantillon:
using Microsoft.Office.Interop.Excel;
string filename = "C:\romil.xlsx";
object missing = System.Reflection.Missing.Value;
Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook wb =excel.Workbooks.Open(filename, missing, missing, missing, missing,missing, missing, missing, missing, missing, missing, missing, missing, missing, missing);
ArrayList sheetname = new ArrayList();
foreach (Microsoft.Office.Interop.Excel.Worksheet sheet in wb.Sheets)
{
sheetname.Add(sheet.Name);
}
je ne vois pas toute la documentation qui dit l'ordre dans l'app.xml est garanti à l'ordre des feuilles. C'est probablement le cas, mais pas selon la spécification OOXML.
Le classeur.fichier xml, d'autre part, comprend les sheetId attribut, qui détermine la séquence de 1 au nombre de feuilles. Ceci est conforme à la spécification OOXML. classeur.xml est décrit comme le lieu où la séquence des feuilles est conservé.
donc, je lis le cahier d'exercices.xml après qu'il est extrait du XLSX serait ma recommandation. PAS d'application.XML. Au lieu de docProps / app.xml, utilisez xl/classeur.xml et regarder l'élément, comme montré ici-
`
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
<fileVersion appName="xl" lastEdited="5" lowestEdited="5" rupBuild="9303" />
<workbookPr defaultThemeVersion="124226" />
- <bookViews>
<workbookView xWindow="120" yWindow="135" windowWidth="19035" windowHeight="8445" />
</bookViews>
- <sheets>
<sheet name="By song" sheetId="1" r:id="rId1" />
<sheet name="By actors" sheetId="2" r:id="rId2" />
<sheet name="By pit" sheetId="3" r:id="rId3" />
</sheets>
- <definedNames>
<definedName name="_xlnm._FilterDatabase" localSheetId="0" hidden="1">'By song'!$A:$O</definedName>
</definedNames>
<calcPr calcId="145621" />
</workbook>
`
essayez ceci. Voici le code pour obtenir les noms des feuilles dans l'ordre.
private Dictionary<int, string> GetExcelSheetNames(string fileName)
{
Excel.Application _excel = null;
Excel.Workbook _workBook = null;
Dictionary<int, string> excelSheets = new Dictionary<int, string>();
try
{
object missing = Type.Missing;
object readOnly = true;
Excel.XlFileFormat.xlWorkbookNormal
_excel = new Excel.ApplicationClass();
_excel.Visible = false;
_workBook = _excel.Workbooks.Open(fileName, 0, readOnly, 5, missing,
missing, true, Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, true, missing);
if (_workBook != null)
{
int index = 0;
foreach (Excel.Worksheet sheet in _workBook.Sheets)
{
// Can get sheet names in order they are in workbook
excelSheets.Add(++index, sheet.Name);
}
}
}
catch (Exception e)
{
return null;
}
finally
{
if (_excel != null)
{
if (_workBook != null)
_workBook.Close(false, Type.Missing, Type.Missing);
_excel.Application.Quit();
}
_excel = null;
_workBook = null;
}
return excelSheets;
}