@@ -244,7 +244,7 @@ public N5Reader openFSReader(final String path) {
244244 @ Deprecated
245245 public N5Reader openZarrReader (final String path ) {
246246
247- return openN5ContainerWithStorageFormat (StorageFormat .ZARR2 , path , this ::openReader );
247+ return openN5ContainerWithStorageFormat (StorageFormat .ZARR , path , this ::openReader );
248248 }
249249
250250 /**
@@ -430,17 +430,37 @@ public N5Reader openReader(@Nullable final StorageFormat storage, @Nullable fina
430430 switch (storage ) {
431431 case N5 :
432432 return new N5KeyValueReader (access , containerPath , gsonBuilder , cacheAttributes );
433- case ZARR :
433+ case ZARR3 :
434434 return new ZarrV3KeyValueReader (access ,containerPath , gsonBuilder , cacheAttributes );
435435 case ZARR2 :
436436 return new ZarrKeyValueReader (access , containerPath , gsonBuilder , zarrMapN5DatasetAttributes , zarrMergeAttributes , cacheAttributes );
437+ case ZARR :
438+ return newGenericZarrReader (access , location );
437439 case HDF5 :
438440 return new N5HDF5Reader (containerPath , hdf5OverrideBlockSize , gsonBuilder , hdf5DefaultBlockSize );
439441 }
440442 return null ;
441443 }
442444 }
443445
446+ /**
447+ * Open a zarr as N5Reader at the given {@code access} and {@code location}.
448+ * Will prefer returning the newest version of zarr that is found at the location.
449+ *
450+ * @param access to the key-value access backend
451+ * @param location of the zarr container
452+ * @return an N5Reader
453+ */
454+ private N5Reader newGenericZarrReader (final KeyValueAccess access , final URI location ) {
455+ for (StorageFormat zarrFormat : List .of (ZARR3 , ZARR2 )) {
456+ try {
457+ return openReader (zarrFormat , access , location );
458+ } catch (Exception ignored ) {
459+ }
460+ }
461+ throw new N5Exception ("Unable to open Zarr reader at " + location .toString () + " as N5Reader" );
462+ }
463+
444464 /**
445465 * Open an {@link N5Writer} for N5 Container.
446466 * <p>
@@ -473,7 +493,7 @@ public N5Writer openFSWriter(final String path) {
473493 @ Deprecated
474494 public N5Writer openZarrWriter (final String path ) {
475495
476- return openN5ContainerWithStorageFormat (StorageFormat .ZARR2 , path , this ::openWriter );
496+ return openN5ContainerWithStorageFormat (StorageFormat .ZARR , path , this ::openWriter );
477497 }
478498
479499 /**
@@ -636,12 +656,14 @@ public N5Writer openWriter(@Nullable final StorageFormat storage, @Nullable fina
636656
637657 final String containerLocation = location .toString ();
638658 switch (storage ) {
639- case ZARR :
659+ case ZARR3 :
640660 final ZarrV3KeyValueWriter writer = new ZarrV3KeyValueWriter (access , containerLocation , gsonBuilder , cacheAttributes );
641661 writer .setDimensionSeparator (zarrDimensionSeparator );
642662 return writer ;
643663 case ZARR2 :
644664 return new ZarrKeyValueWriter (access , containerLocation , gsonBuilder , zarrMapN5DatasetAttributes , zarrMergeAttributes , zarrDimensionSeparator , cacheAttributes );
665+ case ZARR :
666+ return newGenericZarrWriter (access , location );
645667 case N5 :
646668 return new N5KeyValueWriter (access , containerLocation , gsonBuilder , cacheAttributes );
647669 case HDF5 :
@@ -651,6 +673,37 @@ public N5Writer openWriter(@Nullable final StorageFormat storage, @Nullable fina
651673 return null ;
652674 }
653675
676+ /**
677+ * Try to get a zarr writer at the given location and access.
678+ * If a container exists at the location, load that version as a writer if possible.
679+ * If no container exists, create a new writer with the newest zarr version.
680+ *
681+ * @param access to the key-value backend
682+ * @param location of the zarr writer
683+ * @return the zarr writer
684+ */
685+ private N5Writer newGenericZarrWriter (final KeyValueAccess access , final URI location ) {
686+ List <StorageFormat > zarrFormats = List .of (ZARR3 , ZARR2 );
687+ for (StorageFormat zarrFormat : zarrFormats ) {
688+ /* we dont care about the read, but we do want to prefer a writer over a container that
689+ * exists, rather than creating a new writer; the only way to check is to see if
690+ * we can get a valid reader. If we can, try the writer. */
691+ try (N5Reader ignore = openReader (zarrFormat , access , location )) {
692+ return openWriter (zarrFormat , access , location );
693+ } catch (Exception ignored ) {
694+ }
695+ }
696+ /* However, if we have no valid readers, then try and return the first valid (created) writer */
697+ for (StorageFormat zarrFormat : zarrFormats ) {
698+ try {
699+ return openWriter (zarrFormat , access , location );
700+ } catch (Exception ignored ) {
701+ }
702+ }
703+
704+ throw new N5Exception ("Unable to open Zarr writer at " + location .toString () + " as N5Reader" );
705+ }
706+
654707 private <T extends N5Reader > T openN5ContainerWithStorageFormat (
655708 final StorageFormat format ,
656709 final String uri ,
0 commit comments