public void Open(Action <double> progress = null)
        {
            Dictionary <long, RawReaderMode> timestampDict = new Dictionary <long, RawReaderMode>();

            if (!_Remote)
            {
                _ZipFile    = new FileStream(_FileName, FileMode.Open);
                _ZipArchive = new ZipArchive(_ZipFile, ZipArchiveMode.Read);

                if (_Mode.HasFlag(RawReaderMode.Imu0))
                {
                    ZipArchiveEntry entry = _ZipArchive.GetEntry("imu0.csv");
                    using (StreamReader reader = new StreamReader(entry.Open()))
                    {
                        string content = reader.ReadToEnd();
                        ParseImu(content, true, timestampDict);
                    }
                }
                if (_Mode.HasFlag(RawReaderMode.Camera0))
                {
                    foreach (ZipArchiveEntry entry in _ZipArchive.Entries)
                    {
                        if (entry.FullName.StartsWith("cam0\\"))
                        {
                            long timestamp = long.Parse(entry.Name.Replace(".png", ""), CultureInfo.InvariantCulture);

                            if (timestampDict.ContainsKey(timestamp))
                            {
                                timestampDict[timestamp] |= RawReaderMode.Camera0;
                            }
                            else
                            {
                                timestampDict.Add(timestamp, RawReaderMode.Camera0);
                            }
                        }
                    }
                    ZipArchiveEntry camentry = _ZipArchive.GetEntry("cam0.csv");
                    if (camentry != null)
                    {
                        using (StreamReader reader = new StreamReader(camentry.Open()))
                        {
                            string content   = reader.ReadToEnd();
                            bool   skipFirst = true;
                            foreach (string line in content.Split('\n'))
                            {
                                if (skipFirst)
                                {
                                    skipFirst = false;
                                }
                                else
                                {
                                    string[] values = line.Split(',');
                                    if (values.Length == 2)
                                    {
                                        long timestamp = long.Parse(values[0], CultureInfo.InvariantCulture);

                                        double exposureTime = double.Parse(values[1], CultureInfo.InvariantCulture);
                                        _CamCache.Add(timestamp, exposureTime);
                                    }
                                }
                            }
                        }
                    }
                }
                _Length = TimeSpan.FromMilliseconds((timestampDict.Keys.Max() - timestampDict.Keys.Min()) / (1000 * 1000));
            }
            else
            {
                string tempfile = Path.GetTempFileName();
                _RemoteDataStore.DownloadFile(_FileName, tempfile, delegate(double percent)
                {
                    progress?.Invoke(percent * 0.5);
                });

                bool skipFirst = true;
                int  i         = 0;
                int  count     = File.ReadLines(tempfile).Count();
                foreach (string line in File.ReadLines(tempfile))
                {
                    i++;
                    if (skipFirst)
                    {
                        skipFirst = false;
                    }
                    else
                    {
                        ParseImuLine(line, false, timestampDict);
                    }
                    if (i % 100 == 0)
                    {
                        progress?.Invoke(0.5 + ((double)i / count) * 0.5);
                    }
                }
                File.Delete(tempfile);
            }

            IEnumerable <KeyValuePair <long, RawReaderMode> > temp = timestampDict.OrderBy(c => c.Key);

            _Timestamps  = temp.Select(c => c.Key).ToList();
            _ReaderModes = temp.Select(c => c.Value).ToList();

            if (_Timestamps.Count >= 2)
            {
                _DeltaTimeMs = (int)Math.Round(_Timestamps.Take(_Timestamps.Count - 1).Select((v, i) => _Timestamps[i + 1] - v).Sum() / ((_Timestamps.Count - 1) * 1000 * 1000.0));
            }
            else
            {
                _DeltaTimeMs = 1000 / 200;
            }
        }