Если не вдаваться в подробности, попадаются файлы .xlsx которые названы как .xls и наоборот, .xls которые названы как .xlsx. Так же есть такие которые соответствуют своим расширением.
В общем надо пройтись по файлам и переименовать их правильно, но я не нашел как определить формат файла не опираясь на расширение в его названии
По шапке. Файлы нового экселя xlsx начинаются PK - сигнатурой zip-а 50 4B
. С такой сигнатурой могут быть не только xlsx а ещё и docx да и zip архивы, нужно вычитывать список упакованых файлов, для уточнения.
Файлы .xls - бывают двух типов, "новые" xls (обычно именно такие встречаются).
Они имеют сигнатуру D0 CF 1 E0 A1 B1 1A E1
(на самом деле это сигнатура документа офис, для полее подробной идентификации, т.е. doc и xls будут иметь одинаковую сигнатуру, нужно искать "главное" вложение в biff обвертке, и проверять там сигнатуру, либо по списку файлов biff-обвертки), и соовсем старые (до 7 версии, 6-тая не была в обиходе) имеют сигнатуру 09 08
Например можно так
byte[] xlsDoc = f(); // Загрузили документ в байты
if ((xlsDoc[0]==0x50) && (xlsDoc[1]==0x4B)) {
// Новый ексель
}
else if ((xlsDoc[0]==0xD0) && (xlsDoc[1]==0xCF) /*...*/) {
// Офис 97
}
else if ((xlsDoc[0]==9) && (xlsDoc[1]==8)) {
// Старый одностраничный
} else {
// В других случаях - думаю что мусор
}
Т.к. файл может быть большой, то лучше вычитать первые 16 байт, и их проанализировать, а потом вернуть Stream.Position
в ноль.
Ещё с excel мне попадались приколы
<?xml
- файл с excel (если в excel сохранить файл как xml)<html
- часто советуют такой файл делать в интернете javascipt-ом php и т п, - таблица с <td>
<tr>
тегами и определенными приписками.Ссылки на сигнатуры
Как вариант, в Windows для определения, является ли файл корректным XLS-файлом, можно использовать Structured Storage API. Согласно спецификации, формат XLS - это файл формата Structured Storage, который содержит поток с именем Workbook.
MS-XLS: Excel Binary File Format Structure, пункт 2.1.2:
A file of the type specified by this document consists of storages and streams as specified in [MS-CFB]...
A workbook MUST contain the workbook stream...
Можно использовать следующий код для проверки на XLS, на основе этого правила:
using System;
using System.Collections;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
class Program
{
[DllImport("ole32.dll")]
static extern int StgOpenStorageEx(
[MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
uint grfMode,
uint stgfmt,
uint grfAttrs,
IntPtr pStgOptions,
IntPtr reserved2,
[In] ref Guid riid,
out IStorage ppObjectOpen);
const uint STGM_DIRECT = 0;
const uint STGM_READ = 0;
const uint STGM_SHARE_EXCLUSIVE = 0x10;
const uint STGFMT_STORAGE = 0;
const uint PID_FIRST_USABLE = 2;
const uint STGC_DEFAULT = 0;
[Guid("0000000B-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IStorage
{
void a();
[PreserveSig]
int OpenStream(string pwcsName,
IntPtr reserved1,
uint grfMode,
uint reserved2,
[MarshalAs(UnmanagedType.Interface)] out object ppstm);
void CreateStorage(string pwcsName, uint grfMode, uint reserved1, uint reserved2, out IStorage ppstg);
void OpenStorage(string pwcsName, IStorage pstgPriority, uint grfMode, IntPtr snbExclude, uint reserved, out IStorage ppstg);
void CopyTo( uint ciidExclude, Guid[] rgiidExclude, IntPtr snbExclude, IStorage pstgDest);
void MoveElementTo(string pwcsName, IStorage pstgDest, string pwcsNewName, uint grfFlags);
void Commit( uint grfCommitFlags);
void Revert();
void b();
void DestroyElement(string pwcsName);
void RenameElement(string pwcsOldName, string pwcsNewName);
void c();
void SetClass( ref Guid clsid);
void SetStateBits( uint grfStateBits, uint grfMask);
void d();
}
public static bool IsXLS(string path)
{
IStorage pStorage = null;
object o = null;
int hr;
Guid guidStorage = typeof(IStorage).GUID;
try
{
//открываем файл
hr = StgOpenStorageEx(path, STGM_READ | STGM_SHARE_EXCLUSIVE, STGFMT_STORAGE,
0, IntPtr.Zero, IntPtr.Zero, ref guidStorage, out pStorage);
if (hr != 0) return false; //NOT Structured storage file
//открываем поток
hr = pStorage.OpenStream("Workbook", IntPtr.Zero, STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE, 0, out o);
return hr == 0;
}
finally
{
//освобождение ресурсов
if (pStorage != null) Marshal.ReleaseComObject(pStorage);
if (o != null) Marshal.ReleaseComObject(o);
}
}
}
}
Так как файл XLSX является ZIP-архивом определенной структуры, можно применить для проверки ту же логику, и воспользоваться любой библиотекой для работы с ZIP-архивами (в .NET 4.5+ есть встроенная System.IO.Compression).
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Не компилируется в apk, ошибка CommandInvokationFailure: Gradle build failedРаньше решалось это в настройке Build System - надо было Gradle на Internal поменять, а теперь в новой...
Поискал по сайту и ответа на мой вопрос я не нашел, поэтому решил создать новую темуУ меня есть полноэкранный Grid в котором находится usercontrol...