From e5a65e87c91992a0e35ee655922511919f6ee42c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=82=96=E5=B2=A9=28=E7=A7=BB=E5=8A=A8=E5=BC=80=E5=8F=91?= =?UTF-8?q?=E7=BB=84=29?= Date: Mon, 12 Jul 2021 09:46:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E8=A7=86=E9=A2=91?= =?UTF-8?q?=E6=8B=8D=E6=91=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 7 +- app/src/main/AndroidManifest.xml | 1 + .../outdoor/activity/PictureActivity.java | 213 +++- .../com/navinfo/outdoor/api/Constant.java | 2 +- .../outdoor/util/AWMp4ParserHelper.java | 185 +++ .../com/navinfo/outdoor/util/FileUtils.java | 1003 +++++++++++++++++ .../com/navinfo/outdoor/util/IOUtils.java | 98 ++ .../com/navinfo/outdoor/util/StringUtils.java | 703 ++++++++++++ app/src/main/res/layout/activity_picture.xml | 7 +- 9 files changed, 2190 insertions(+), 29 deletions(-) create mode 100644 app/src/main/java/com/navinfo/outdoor/util/AWMp4ParserHelper.java create mode 100644 app/src/main/java/com/navinfo/outdoor/util/FileUtils.java create mode 100644 app/src/main/java/com/navinfo/outdoor/util/IOUtils.java create mode 100644 app/src/main/java/com/navinfo/outdoor/util/StringUtils.java diff --git a/app/build.gradle b/app/build.gradle index 10ef29a..8b7ec08 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -84,7 +84,7 @@ dependencies { //三级选择 implementation 'com.airsaid.library:pickerview:1.0.3' //省市区 https://github.com/Bigkoo/Android-PickerView - compile 'com.contrarywind:Android-PickerView:4.1.6' + implementation 'com.contrarywind:Android-PickerView:4.1.6' implementation 'com.contrarywind:Android-PickerView:4.1.8' /* //加载html implementation 'com.github.sendtion:XRichText:1.9.4'*/ @@ -94,7 +94,7 @@ dependencies { implementation 'com.kongzue.dialog_v3x:dialog:3.2.4' //xRecyclerview下拉刷新控件 implementation project(':xrecyclerview') - //拍照功能 + //拍照功能 https://github.com/natario1/CameraView implementation 'com.otaliastudios:cameraview:2.7.0' //抽屉控件 https://github.com/umano/AndroidSlidingUpPanel @@ -120,4 +120,7 @@ dependencies { implementation "androidx.room:room-rxjava2:$room_version" implementation "androidx.room:room-guava:$room_version" testImplementation "androidx.room:room-testing:$room_version" + + // 视频拼接 https://blog.csdn.net/u011520181/article/details/89324292 + implementation 'com.googlecode.mp4parser:isoparser:1.1.21' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bcfdba8..1b53b41 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -38,6 +38,7 @@ android:label="@string/app_name" android:networkSecurityConfig="@xml/network_security_config" android:requestLegacyExternalStorage="true" + android:largeHeap="true" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.WhiteScreen"> diff --git a/app/src/main/java/com/navinfo/outdoor/activity/PictureActivity.java b/app/src/main/java/com/navinfo/outdoor/activity/PictureActivity.java index 7c6ab3f..b0de988 100644 --- a/app/src/main/java/com/navinfo/outdoor/activity/PictureActivity.java +++ b/app/src/main/java/com/navinfo/outdoor/activity/PictureActivity.java @@ -10,6 +10,7 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.location.Location; +import android.media.MediaMetadataRetriever; import android.os.Looper; import android.os.Message; import android.util.DisplayMetrics; @@ -18,21 +19,19 @@ import android.view.View; import android.view.ViewGroup; import android.widget.Button; -import android.widget.ImageButton; +import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.Toast; -import com.hjq.permissions.OnPermissionCallback; -import com.hjq.permissions.Permission; -import com.hjq.permissions.XXPermissions; import com.navinfo.outdoor.R; import com.navinfo.outdoor.api.Constant; import com.navinfo.outdoor.base.BaseActivity; +import com.navinfo.outdoor.util.AWMp4ParserHelper; +import com.navinfo.outdoor.util.FileUtils; import com.navinfo.outdoor.util.MyTecentLocationSource; -import com.navinfo.outdoor.util.NetWorkUtils; import com.navinfo.outdoor.util.SdkFolderCreate; -import com.navinfo.outdoor.util.ToastUtil; import com.otaliastudios.cameraview.CameraException; import com.otaliastudios.cameraview.CameraListener; import com.otaliastudios.cameraview.CameraLogger; @@ -44,10 +43,14 @@ import com.otaliastudios.cameraview.VideoResult; import com.otaliastudios.cameraview.controls.Engine; import com.otaliastudios.cameraview.controls.Mode; -import com.tencent.map.geolocation.TencentLocation; +import com.otaliastudios.cameraview.frame.Frame; +import com.otaliastudios.cameraview.frame.FrameProcessor; +import com.otaliastudios.cameraview.size.AspectRatio; +import com.otaliastudios.cameraview.size.Size; +import com.otaliastudios.cameraview.size.SizeSelector; +import com.otaliastudios.cameraview.size.SizeSelectors; import com.tencent.tencentmap.mapsdk.maps.CameraUpdate; import com.tencent.tencentmap.mapsdk.maps.CameraUpdateFactory; -import com.tencent.tencentmap.mapsdk.maps.MapView; import com.tencent.tencentmap.mapsdk.maps.TencentMap; import com.tencent.tencentmap.mapsdk.maps.TextureMapView; import com.tencent.tencentmap.mapsdk.maps.UiSettings; @@ -65,35 +68,60 @@ import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.FileDescriptor; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; + import static com.tencent.tencentmap.mapsdk.maps.model.MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE; public class PictureActivity extends BaseActivity implements View.OnClickListener { private static final CameraLogger LOG = CameraLogger.create("Picture"); private CameraView camera; -// private ImageButton capturePicture; private long captureTime = 0; private android.widget.Button btnSwitch; private TencentMap tencentMap; private MyLocationStyle locationStyle; private TextureMapView ivMap; - private Button captureVideo, stopVideo; - private Button btnVideo; + private CheckBox captureVideo; // 拍摄视频 + private Button btnVideo, stopVideo; private ImageView ivPic; + private String finalVideoPath; // 摄像后最终保存的文件名 + private File tmpFile; // 合并文件的临时文件路径 + private Timer timer; + private CsvTimerTask timerTask; // 执行定时写入csv文件的task + private DateFormat formatter; + private final long period = 2; // 记录csv文件的间隔时间,单位为秒 @Override protected int getLayout() { EventBus.getDefault().register(this); + tmpFile = new File(Constant.PICTURE_FOLDER, "temp.mp4"); + formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return R.layout.activity_picture; } @Override protected void initView() { super.initView(); + + if (getIntent()!=null) { + finalVideoPath = getIntent().getStringExtra(Constant.INTENT_VIDEO_PATH); + } + if (finalVideoPath == null) { + finalVideoPath = Constant.PICTURE_FOLDER+"/final.mp4"; + } + + timer = new Timer(); + this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); ivMap = (TextureMapView) findViewById(R.id.iv_map); ivPic = findViewById(R.id.iv_pic); @@ -108,13 +136,53 @@ public class PictureActivity extends BaseActivity implements View.OnClickListene camera = findViewById(R.id.camera); camera.setOnClickListener(this::onClick); captureVideo = findViewById(R.id.capuretVideo); - captureVideo.setOnClickListener(this::onClick); + captureVideo.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (isChecked) { // 开始采集,设置按钮文字内容为“结束采集” + captureVideo.setText("暂停采集"); + + startTakenVideo(); // 开始采集视频 + + /** + * 获取当前视频的时间,记录csv文件时使用 + * */ + long currentTime = AWMp4ParserHelper.getInstance().getVedioTotalTime(new File(finalVideoPath)); + timerTask = new CsvTimerTask(new File(finalVideoPath+".txt")); + timerTask.setCurrentVideoTime(currentTime/1000); + + // 开始采集,每隔2秒实时记录位置信息、视频时间以及设备时间 + timer.schedule(timerTask, 0, period*1000); + } else { + captureVideo.setText("开始采集"); + timerTask.cancel(); + stopTakenVideo(); + } + } + }); stopVideo = findViewById(R.id.btn_stop_video); stopVideo.setOnClickListener(this::onClick); //拍照权限 camera.setLifecycleOwner(this); camera.setEngine(Engine.CAMERA1); +// camera.setVideoBitRate(5); + camera.setPreviewFrameRate(5); // 设置预览视频的帧率 + + // 设置视频可用的宽高size + SizeSelector width = SizeSelectors.maxWidth(1920); + SizeSelector height = SizeSelectors.maxHeight(1024); + SizeSelector dimensions = SizeSelectors.and(width, height); // Matches sizes bigger than 1000x2000. + SizeSelector ratio = SizeSelectors.aspectRatio(AspectRatio.of(1, 1), 0); // Matches 1:1 sizes. + + SizeSelector result = SizeSelectors.or( + SizeSelectors.and(ratio, dimensions), // Try to match both constraints + ratio, // If none is found, at least try to match the aspect ratio + SizeSelectors.biggest() // If none is found, take the biggest + ); + camera.setVideoSize(result); + camera.setVideoBitRate(3000*1024); +// camera.setAudioBitRate(); //设置拍照的宽高 SdkFolderCreate.mkdirs(Constant.PICTURE_FOLDER); @@ -127,12 +195,18 @@ public class PictureActivity extends BaseActivity implements View.OnClickListene // uiSettings.setAllGesturesEnabled(false); setLocMarkerStyle(); // 设置当前位置显示样式 +// camera.addFrameProcessor(new FrameProcessor() { +// @Override +// public void process(@NonNull Frame frame) { +// Log.e("PictureActivity", frame.getTime()+""); +// } +// }); + //相机预览监听 camera.addCameraListener(new CameraListener() { @Override public void onPictureTaken(@NonNull @NotNull PictureResult result) { super.onPictureTaken(result); - DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); String format = formatter.format(calendar.getTime()); @@ -150,15 +224,38 @@ public class PictureActivity extends BaseActivity implements View.OnClickListene long callbackTime = System.currentTimeMillis(); captureTime = callbackTime - 300; Log.d("captureTime", captureTime + ""); - } //录像监听 @Override public void onVideoTaken(@NonNull @NotNull VideoResult result) { super.onVideoTaken(result); - Toast.makeText(PictureActivity.this, "停止摄像", Toast.LENGTH_SHORT).show(); - finish(); + Toast.makeText(PictureActivity.this, "暂停摄像", Toast.LENGTH_SHORT).show(); + if (result!=null) { + File currentFile = result.getFile(); + if (finalVideoPath!=null) { // 有指定的视频文件名称,合并文件 + if (new File(finalVideoPath).exists()) { + List spliteFileList = new ArrayList<>(); + spliteFileList.add(finalVideoPath); + spliteFileList.add(currentFile.getAbsolutePath()); + try { + AWMp4ParserHelper.getInstance().mergeVideos(spliteFileList, tmpFile.getAbsolutePath()); + if (tmpFile.exists()) { + File finalVideoFile = new File(finalVideoPath); + finalVideoFile.delete(); + currentFile.delete(); + tmpFile.renameTo(finalVideoFile); + } else { + Toast.makeText(PictureActivity.this, "视频合并失败!", Toast.LENGTH_SHORT).show(); + } + } catch (Exception e) { + Log.e("PictureActivity", e.getMessage()); + } + } else { + currentFile.renameTo(new File(finalVideoPath)); + } + } + } } @Override @@ -203,20 +300,49 @@ public class PictureActivity extends BaseActivity implements View.OnClickListene case R.id.btn_switch: btnSwich(); break; - case R.id.capuretVideo: - DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - Calendar calendar = Calendar.getInstance(); - calendar.setTimeInMillis(System.currentTimeMillis()); - String format = formatter.format(calendar.getTime()); - //文件 - File file = new File(Constant.PICTURE_FOLDER, format + ".mp4"); - camera.takeVideo(file); - break; +// case R.id.capuretVideo: +// startTakenVideo(); // 开始拍摄视频 +// break; case R.id.btn_stop_video: + this.finish(); + break; } } + private void startTakenVideo() { + if (camera.isTakingVideo()) { + Toast.makeText(this, "已经在拍摄中...", Toast.LENGTH_SHORT).show(); + return; + } + DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(System.currentTimeMillis()); + String formatVideoName = formatter.format(calendar.getTime()); + //文件 + File file = new File(Constant.PICTURE_FOLDER, formatVideoName + ".mp4"); + if (file.exists()) { + try { + FileOutputStream fo = new FileOutputStream(file); + FileDescriptor fileDescriptor = fo.getFD(); + camera.takeVideo(fileDescriptor); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } else { + camera.takeVideo(file); + } + + } + + private void stopTakenVideo() { + if (camera.isTakingVideo()) { + camera.stopVideo(); + } + } + private Bitmap getBitMap(int resourceId) { Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resourceId); int width = bitmap.getWidth(); @@ -292,6 +418,7 @@ public class PictureActivity extends BaseActivity implements View.OnClickListene @Override protected void onDestroy() { super.onDestroy(); + stopTakenVideo(); camera.destroy(); if (EventBus.getDefault().isRegistered(this)) { EventBus.getDefault().unregister(this); @@ -315,4 +442,40 @@ public class PictureActivity extends BaseActivity implements View.OnClickListene } } + /** + * 记录视频拍摄的时间及经纬度 + */ + private class CsvTimerTask extends TimerTask { + private File csvFile; + private long currentVideoTime; // 记录当前的视频时间 + + public CsvTimerTask(File csvFile) { + this.csvFile = csvFile; + if (!csvFile.exists()) { + csvFile.getParentFile().mkdirs(); + } + } + + public void setCurrentVideoTime(long currentVideoTime) { + this.currentVideoTime = currentVideoTime; + } + + @Override + public void run() { + // 记录当前时间、视频时间、以及当前经纬度信息 + StringBuffer sb = new StringBuffer(); + sb.append(formatter.format(new Date())); // 记录当前时间 + sb.append(","); + sb.append(currentVideoTime) ;// 记录视频时间 + sb.append(","); + sb.append(Constant.currentLocation.getLatitude()); + sb.append(","); + sb.append(Constant.currentLocation.getLongitude()); + sb.append("\r\n"); + FileUtils.writeFile(csvFile.getAbsolutePath(), sb.toString(), true); + currentVideoTime = currentVideoTime+period; // + } + } + + } \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/outdoor/api/Constant.java b/app/src/main/java/com/navinfo/outdoor/api/Constant.java index 1630c68..aca03a6 100644 --- a/app/src/main/java/com/navinfo/outdoor/api/Constant.java +++ b/app/src/main/java/com/navinfo/outdoor/api/Constant.java @@ -94,5 +94,5 @@ public class Constant { public static JobSearchBean jobSearchBean;//数据 public static MapView treasureMap; - + public static final String INTENT_VIDEO_PATH = "INTENT_VIDEO_PATH"; // 拍照界面指定的视频文件保存位置 } diff --git a/app/src/main/java/com/navinfo/outdoor/util/AWMp4ParserHelper.java b/app/src/main/java/com/navinfo/outdoor/util/AWMp4ParserHelper.java new file mode 100644 index 0000000..5ec4ce5 --- /dev/null +++ b/app/src/main/java/com/navinfo/outdoor/util/AWMp4ParserHelper.java @@ -0,0 +1,185 @@ +package com.navinfo.outdoor.util; + +import android.content.Context; +import android.graphics.Bitmap; +import android.media.MediaMetadataRetriever; +import android.util.Log; +import android.widget.ImageView; + +import androidx.annotation.NonNull; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; +import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; +import com.bumptech.glide.load.resource.bitmap.VideoDecoder; +import com.bumptech.glide.request.RequestOptions; +import com.coremedia.iso.boxes.Container; +import com.googlecode.mp4parser.authoring.Movie; +import com.googlecode.mp4parser.authoring.Track; +import com.googlecode.mp4parser.authoring.builder.DefaultMp4Builder; +import com.googlecode.mp4parser.authoring.container.mp4.MovieCreator; +import com.googlecode.mp4parser.authoring.tracks.AppendTrack; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * Author: AlanWang4523. + * Date: 19/4/15 01:46. + * Mail: alanwang4523@gmail.com + */ +public class AWMp4ParserHelper { + private static AWMp4ParserHelper instance; + + public static AWMp4ParserHelper getInstance() { + if (instance == null) { + instance = new AWMp4ParserHelper(); + } + return instance; + } + + private final static String PREFIX_VIDEO_HANDLER = "vide"; + private final static String PREFIX_AUDIO_HANDLER = "soun"; + /** + * 合并视频 + * @param inputVideos + * @param outputPath + * @throws IOException + */ + public static void mergeVideos(List inputVideos, String outputPath) throws IOException { + List inputMovies = new ArrayList<>(); + for (String input : inputVideos) { + inputMovies.add(MovieCreator.build(input)); + } + + List videoTracks = new LinkedList<>(); + List audioTracks = new LinkedList<>(); + + for (Movie m : inputMovies) { + for (Track t : m.getTracks()) { + if (PREFIX_AUDIO_HANDLER.equals(t.getHandler())) { + audioTracks.add(t); + } + if (PREFIX_VIDEO_HANDLER.equals(t.getHandler())) { + videoTracks.add(t); + } + } + } + + Movie outputMovie = new Movie(); + if (audioTracks.size() > 0) { + outputMovie.addTrack(new AppendTrack(audioTracks.toArray(new Track[audioTracks.size()]))); + } + if (videoTracks.size() > 0) { + outputMovie.addTrack(new AppendTrack(videoTracks.toArray(new Track[videoTracks.size()]))); + } + + Container out = new DefaultMp4Builder().build(outputMovie); + + FileChannel fc = new RandomAccessFile(outputPath, "rw").getChannel(); + out.writeContainer(fc); + fc.close(); + } + + /** + * 获取mp4视频播放时长 + * */ + /** + * 返回视频播放总时长 + * @param vedioFile + * @return + */ + public long getVedioTotalTime(File vedioFile){ + if (!vedioFile.exists()){ + Log.e("getVedioTotalTime","视频文件不存在"); + return 0; + } + MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + retriever.setDataSource(vedioFile.getAbsolutePath()); + String timeString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); + long time = Long.valueOf(timeString); + return time; + } + + /** + * 获取网络视频第一帧 + * + * @param videoUrl + * @return + */ + public void loadFirst(String videoUrl, @NonNull ImageView cover) { + Bitmap bitmap = null; + MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + try { + //根据url获取缩略图 + retriever.setDataSource(videoUrl, new HashMap()); + //获得第一帧图片 + bitmap = retriever.getFrameAtTime(); + } catch (IllegalArgumentException e) { + //e.printStackTrace(); + Log.e("zhu", e.toString()); + } finally { + retriever.release(); + } + if (bitmap != null) { + cover.setImageBitmap(bitmap); + } + } + + /** + *   context 上下文 + *   uri 视频地址 + *   imageView 设置image + *   frameTimeMicros 获取某一时间帧 + */ + public void loadFirstWithGlide(final Context context, String uri, ImageView imageView, long frameTimeMicros) { + RequestOptions requestOptions = RequestOptions.frameOf(frameTimeMicros); + requestOptions.set(VideoDecoder.FRAME_OPTION, MediaMetadataRetriever.OPTION_CLOSEST); + requestOptions.transform(new BitmapTransformation() { + @Override + protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) { + return toTransform; + } + + @Override + public void updateDiskCacheKey(MessageDigest messageDigest) { + try { + messageDigest.update((context.getPackageName() + "RotateTransform").getBytes("utf-8")); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + Glide.with(context).load(uri).apply(requestOptions).into(imageView); + } + + /** + * 获取本地视频的第一帧 + * + * @param localPath + * @return + */ + public Bitmap getLocalVideoBitmap(String localPath) { + Bitmap bitmap = null; + MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + try { + //根据文件路径获取缩略图 + retriever.setDataSource(localPath); + //获得第一帧图片 + bitmap = retriever.getFrameAtTime(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } finally { + retriever.release(); + } + return bitmap; + } +} diff --git a/app/src/main/java/com/navinfo/outdoor/util/FileUtils.java b/app/src/main/java/com/navinfo/outdoor/util/FileUtils.java new file mode 100644 index 0000000..ce4777a --- /dev/null +++ b/app/src/main/java/com/navinfo/outdoor/util/FileUtils.java @@ -0,0 +1,1003 @@ +package com.navinfo.outdoor.util; +import android.content.Context; +import android.content.Intent; +import android.content.res.AssetManager; +import android.database.Cursor; +import android.net.Uri; +import android.provider.MediaStore; +import android.text.TextUtils; +import android.webkit.MimeTypeMap; +import android.widget.Toast; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +public class FileUtils { + public final String TAG = "LAZY"; + public final static String FILE_EXTENSION_SEPARATOR = "."; + /** URI类型:file */ + public static final String URI_TYPE_FILE = "file"; + + + private FileUtils() { + throw new AssertionError(); + } + + + /** + * read file + * + * @param filePath 路径 + * @param charsetName The name of a supported {@link + * java.nio.charset.Charset charset} + * @return if file not exist, return null, else return content of file + * @throws RuntimeException if an error occurs while operator + * BufferedReader + */ + public static StringBuilder readFile(String filePath, String charsetName) { + + File file = new File(filePath); + StringBuilder fileContent = new StringBuilder(""); + if (file == null || !file.isFile()) { + return null; + } + + BufferedReader reader = null; + try { + InputStreamReader is = new InputStreamReader( + new FileInputStream(file), charsetName); + reader = new BufferedReader(is); + String line = null; + while ((line = reader.readLine()) != null) { + if (!fileContent.toString().equals("")) { + fileContent.append("\r\n"); + } + fileContent.append(line); + } + return fileContent; + } catch (IOException e) { + throw new RuntimeException("IOException occurred. ", e); + } finally { + IOUtils.close(reader); + } + } + + + /** + * write file + * + * @param filePath 路径 + * @param content 上下文 + * @param append is append, if true, write to the end of file, else clear + * content of file and write into it + * @return return false if content is empty, true otherwise + * @throws RuntimeException if an error occurs while operator FileWriter + */ + public static boolean writeFile(String filePath, String content, boolean append) { + + if (StringUtils.isEmpty(content)) { + return false; + } + + FileWriter fileWriter = null; + try { + makeDirs(filePath); + fileWriter = new FileWriter(filePath, append); + fileWriter.write(content); + return true; + } catch (IOException e) { + throw new RuntimeException("IOException occurred. ", e); + } finally { + IOUtils.close(fileWriter); + } + } + + + /** + * write file + * + * @param filePath 路径 + * @param contentList 集合 + * @param append is append, if true, write to the end of file, else clear + * content of file and write into it + * @return return false if contentList is empty, true otherwise + * @throws RuntimeException if an error occurs while operator FileWriter + */ + public static boolean writeFile(String filePath, List contentList, boolean append) { + + if (contentList.size()==0||null==contentList) { + return false; + } + + FileWriter fileWriter = null; + try { + makeDirs(filePath); + fileWriter = new FileWriter(filePath, append); + int i = 0; + for (String line : contentList) { + if (i++ > 0) { + fileWriter.write("\r\n"); + } + fileWriter.write(line); + } + return true; + } catch (IOException e) { + throw new RuntimeException("IOException occurred. ", e); + } finally { + IOUtils.close(fileWriter); + } + } + + + /** + * write file, the string will be written to the begin of the file + * @param filePath 地址 + * @param content 上下文 + * @return 是否写入成功 + */ + public static boolean writeFile(String filePath, String content) { + + return writeFile(filePath, content, false); + } + + + /** + * write file, the string list will be written to the begin of the file + * @param filePath 地址 + * @param contentList 集合 + * @return 是否写入成功 + */ + public static boolean writeFile(String filePath, List contentList) { + return writeFile(filePath, contentList, false); + + } + + + /** + * write file, the bytes will be written to the begin of the file + * + * @param filePath 路径 + * @param stream 输入流 + * @return 返回是否写入成功 + */ + public static boolean writeFile(String filePath, InputStream stream) { + return writeFile(filePath, stream, false); + + } + + + /** + * write file + * + * @param filePath 路径 + * @param stream the input stream + * @param append if true, then bytes will be written to the + * end + * of the file rather than the beginning + * @return return true + * FileOutputStream + */ + public static boolean writeFile(String filePath, InputStream stream, boolean append) { + + return writeFile(filePath != null ? new File(filePath) : null, stream, + append); + } + + + /** + * write file, the bytes will be written to the begin of the file + * + * @param file 文件对象 + * @param stream 输入流 + * @return 返回是否写入成功 + */ + public static boolean writeFile(File file, InputStream stream) { + return writeFile(file, stream, false); + + } + + + /** + * write file + * + * @param file the file to be opened for writing. + * @param stream the input stream + * @param append if true, then bytes will be written to the + * end + * of the file rather than the beginning + * @return return true + * @throws RuntimeException if an error occurs while operator + * FileOutputStream + */ + public static boolean writeFile(File file, InputStream stream, boolean append) { + OutputStream o = null; + try { + makeDirs(file.getAbsolutePath()); + o = new FileOutputStream(file, append); + byte data[] = new byte[1024]; + int length = -1; + while ((length = stream.read(data)) != -1) { + o.write(data, 0, length); + } + o.flush(); + return true; + } catch (FileNotFoundException e) { + throw new RuntimeException("FileNotFoundException occurred. ", e); + } catch (IOException e) { + throw new RuntimeException("IOException occurred. ", e); + } finally { + IOUtils.close(o); + IOUtils.close(stream); + } + } + + + /** + * move file + * @param sourceFilePath 资源路径 + * @param destFilePath 删除的路径 + */ + public static void moveFile(String sourceFilePath, String destFilePath) { + + if (TextUtils.isEmpty(sourceFilePath) || + TextUtils.isEmpty(destFilePath)) { + throw new RuntimeException( + "Both sourceFilePath and destFilePath cannot be null."); + } + moveFile(new File(sourceFilePath), new File(destFilePath)); + } + + + /** + * move file + * @param srcFile 文件对象 + * @param destFile 对象 + */ + public static void moveFile(File srcFile, File destFile) { + + boolean rename = srcFile.renameTo(destFile); + if (!rename) { + copyFile(srcFile.getAbsolutePath(), destFile.getAbsolutePath()); + deleteFile(srcFile.getAbsolutePath()); + } + } + + + /** + * copy file + * + * @param sourceFilePath 资源路径 + * @param destFilePath 删除的文件 + * @throws RuntimeException if an error occurs while operator + * FileOutputStream + * @return 返回是否成功 + */ + public static boolean copyFile(String sourceFilePath, String destFilePath) { + + InputStream inputStream = null; + try { + inputStream = new FileInputStream(sourceFilePath); + } catch (FileNotFoundException e) { + throw new RuntimeException("FileNotFoundException occurred. ", e); + } + return writeFile(destFilePath, inputStream); + } + + + /** + * read file to string list, a element of list is a line + * + * @param filePath 路径 + * @param charsetName The name of a supported {@link + * java.nio.charset.Charset charset} + * @return if file not exist, return null, else return content of file + * @throws RuntimeException if an error occurs while operator + * BufferedReader + */ + public static List readFileToList(String filePath, String charsetName) { + + File file = new File(filePath); + List fileContent = new ArrayList(); + if (file == null || !file.isFile()) { + return null; + } + + BufferedReader reader = null; + try { + InputStreamReader is = new InputStreamReader( + new FileInputStream(file), charsetName); + reader = new BufferedReader(is); + String line = null; + while ((line = reader.readLine()) != null) { + fileContent.add(line); + } + return fileContent; + } catch (IOException e) { + throw new RuntimeException("IOException occurred. ", e); + } finally { + IOUtils.close(reader); + } + } + + + /** + * + * @param filePath 文件的路径 + * @return 返回文件的信息 + */ + public static String getFileNameWithoutExtension(String filePath) { + + + if (StringUtils.isEmpty(filePath)) { + return filePath; + } + + int extenPosi = filePath.lastIndexOf(FILE_EXTENSION_SEPARATOR); + int filePosi = filePath.lastIndexOf(File.separator); + if (filePosi == -1) { + return (extenPosi == -1 + ? filePath + : filePath.substring(0, extenPosi)); + } + if (extenPosi == -1) { + return filePath.substring(filePosi + 1); + } + return (filePosi < extenPosi ? filePath.substring(filePosi + 1, + extenPosi) : filePath.substring(filePosi + 1)); + } + + + /** + * get file name from path, include suffix + * + *
+     *      getFileName(null)               =   null
+     *      getFileName("")                 =   ""
+     *      getFileName("   ")              =   "   "
+     *      getFileName("a.mp3")            =   "a.mp3"
+     *      getFileName("a.b.rmvb")         =   "a.b.rmvb"
+     *      getFileName("abc")              =   "abc"
+     *      getFileName("c:\\")              =   ""
+     *      getFileName("c:\\a")             =   "a"
+     *      getFileName("c:\\a.b")           =   "a.b"
+     *      getFileName("c:a.txt\\a")        =   "a"
+     *      getFileName("/home/admin")      =   "admin"
+     *      getFileName("/home/admin/a.txt/b.mp3")  =   "b.mp3"
+     * 
+ * + * @param filePath 路径 + * @return file name from path, include suffix + */ + public static String getFileName(String filePath) { + + if (StringUtils.isEmpty(filePath)) { + return filePath; + } + + int filePosi = filePath.lastIndexOf(File.separator); + return (filePosi == -1) ? filePath : filePath.substring(filePosi + 1); + } + + + /** + * get folder name from path + * + *
+     *      getFolderName(null)               =   null
+     *      getFolderName("")                 =   ""
+     *      getFolderName("   ")              =   ""
+     *      getFolderName("a.mp3")            =   ""
+     *      getFolderName("a.b.rmvb")         =   ""
+     *      getFolderName("abc")              =   ""
+     *      getFolderName("c:\\")              =   "c:"
+     *      getFolderName("c:\\a")             =   "c:"
+     *      getFolderName("c:\\a.b")           =   "c:"
+     *      getFolderName("c:a.txt\\a")        =   "c:a.txt"
+     *      getFolderName("c:a\\b\\c\\d.txt")    =   "c:a\\b\\c"
+     *      getFolderName("/home/admin")      =   "/home"
+     *      getFolderName("/home/admin/a.txt/b.mp3")  =   "/home/admin/a.txt"
+     * 
+ * @param filePath 路径 + * @return file name from path, include suffix + */ + public static String getFolderName(String filePath) { + + + if (StringUtils.isEmpty(filePath)) { + return filePath; + } + + int filePosi = filePath.lastIndexOf(File.separator); + return (filePosi == -1) ? "" : filePath.substring(0, filePosi); + } + + + /** + * get suffix of file from path + * + *
+     *      getFileExtension(null)               =   ""
+     *      getFileExtension("")                 =   ""
+     *      getFileExtension("   ")              =   "   "
+     *      getFileExtension("a.mp3")            =   "mp3"
+     *      getFileExtension("a.b.rmvb")         =   "rmvb"
+     *      getFileExtension("abc")              =   ""
+     *      getFileExtension("c:\\")              =   ""
+     *      getFileExtension("c:\\a")             =   ""
+     *      getFileExtension("c:\\a.b")           =   "b"
+     *      getFileExtension("c:a.txt\\a")        =   ""
+     *      getFileExtension("/home/admin")      =   ""
+     *      getFileExtension("/home/admin/a.txt/b")  =   ""
+     *      getFileExtension("/home/admin/a.txt/b.mp3")  =   "mp3"
+     * 
+ * @param filePath 路径 + * @return 信息 + */ + public static String getFileExtension(String filePath) { + + if (StringUtils.isBlank(filePath)) { + return filePath; + } + + int extenPosi = filePath.lastIndexOf(FILE_EXTENSION_SEPARATOR); + int filePosi = filePath.lastIndexOf(File.separator); + if (extenPosi == -1) { + return ""; + } + return (filePosi >= extenPosi) ? "" : filePath.substring(extenPosi + 1); + } + + + /** + * + * @param filePath 路径 + * @return 是否创建成功 + */ + public static boolean makeDirs(String filePath) { + + String folderName = getFolderName(filePath); + if (StringUtils.isEmpty(folderName)) { + return false; + } + + File folder = new File(folderName); + return (folder.exists() && folder.isDirectory()) + ? true + : folder.mkdirs(); + } + + + /** + * + * @param filePath 路径 + * @return 是否创建成功 + */ + public static boolean makeFolders(String filePath) { + return makeDirs(filePath); + + } + + + /** + * + * @param filePath 路径 + * @return 是否存在这个文件 + */ + public static boolean isFileExist(String filePath) { + if (StringUtils.isBlank(filePath)) { + return false; + } + + File file = new File(filePath); + return (file.exists() && file.isFile()); + + } + + + /** + * + * @param directoryPath 路径 + * @return 是否有文件夹 + */ + public static boolean isFolderExist(String directoryPath) { + + if (StringUtils.isBlank(directoryPath)) { + return false; + } + + File dire = new File(directoryPath); + return (dire.exists() && dire.isDirectory()); + } + + + /** + * + * @param path 路径 + * @return 是否删除成功 + */ + public static boolean deleteFile(String path) { + + if (StringUtils.isBlank(path)) { + return true; + } + + File file = new File(path); + if (!file.exists()) { + return true; + } + if (file.isFile()) { + return file.delete(); + } + if (!file.isDirectory()) { + return false; + } + for (File f : file.listFiles()) { + if (f.isFile()) { + f.delete(); + } + else if (f.isDirectory()) { + deleteFile(f.getAbsolutePath()); + } + } + return file.delete(); + } + + + /** + * + * @param path 路径 + * @return 返回文件大小 + */ + public static long getFileSize(String path) { + + if (StringUtils.isBlank(path)) { + return -1; + } + + File file = new File(path); + return (file.exists() && file.isFile() ? file.length() : -1); + } + + + /** + * 保存多媒体数据为文件. + * + * @param data 多媒体数据 + * @param fileName 保存文件名 + * @return 保存成功或失败 + */ + public static boolean save2File(InputStream data, String fileName) { + File file = new File(fileName); + FileOutputStream fos = null; + try { + // 文件或目录不存在时,创建目录和文件. + if (!file.exists()) { + file.getParentFile().mkdirs(); + file.createNewFile(); + } + + // 写入数据 + fos = new FileOutputStream(file); + byte[] b = new byte[1024]; + int len; + while ((len = data.read(b)) > -1) { + fos.write(b, 0, len); + } + fos.close(); + + return true; + } catch (IOException ex) { + + return false; + } + } + + + /** + * 读取文件的字节数组. + * + * @param file 文件 + * @return 字节数组 + */ + public static byte[] readFile4Bytes(File file) { + + // 如果文件不存在,返回空 + if (!file.exists()) { + return null; + } + FileInputStream fis = null; + try { + // 读取文件内容. + fis = new FileInputStream(file); + byte[] arrData = new byte[(int) file.length()]; + fis.read(arrData); + // 返回 + return arrData; + } catch (IOException e) { + + return null; + } finally { + if (fis != null) { + try { + fis.close(); + } catch (IOException e) { + + } + } + } + } + + + /** + * 读取文本文件内容,以行的形式读取 + * + * @param filePathAndName 带有完整绝对路径的文件名 + * @return String 返回文本文件的内容 + */ + public static String readFileContent(String filePathAndName) { + try { + return readFileContent(filePathAndName, null, null, 1024); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + + /** + * 读取文本文件内容,以行的形式读取 + * + * @param filePathAndName 带有完整绝对路径的文件名 + * @param encoding 文本文件打开的编码方式 例如 GBK,UTF-8 + * @param sep 分隔符 例如:#,默认为\n; + * @param bufLen 设置缓冲区大小 + * @return String 返回文本文件的内容 + */ + public static String readFileContent(String filePathAndName, String encoding, String sep, int bufLen) + { + if (filePathAndName == null || filePathAndName.equals("")) { + return ""; + } + if (sep == null || sep.equals("")) { + sep = "\n"; + } + if (!new File(filePathAndName).exists()) { + return ""; + } + StringBuffer str = new StringBuffer(""); + FileInputStream fs = null; + InputStreamReader isr = null; + BufferedReader br = null; + try { + fs = new FileInputStream(filePathAndName); + if (encoding == null || encoding.trim().equals("")) { + isr = new InputStreamReader(fs); + } + else { + isr = new InputStreamReader(fs, encoding.trim()); + } + br = new BufferedReader(isr, bufLen); + + String data = ""; + while ((data = br.readLine()) != null) { + str.append(data).append(sep); + } + } catch (IOException e) { + } finally { + try { + if (br != null) br.close(); + if (isr != null) isr.close(); + if (fs != null) fs.close(); + } catch (IOException e) { + } + } + return str.toString(); + } + + + /** + * 把Assets里的文件拷贝到sd卡上 + * + * @param assetManager AssetManager + * @param fileName Asset文件名 + * @param destinationPath 完整目标路径 + * @return 拷贝成功 + */ + public static boolean copyAssetToSDCard(AssetManager assetManager, String fileName, String destinationPath) { + + try { + InputStream is = assetManager.open(fileName); + FileOutputStream os = new FileOutputStream(destinationPath); + + if (is != null && os != null) { + byte[] data = new byte[1024]; + int len; + while ((len = is.read(data)) > 0) { + os.write(data, 0, len); + } + + os.close(); + is.close(); + } + } catch (IOException e) { + return false; + } + return true; + } + + + /** + * 调用系统方式打开文件. + * + * @param context 上下文 + * @param file 文件 + */ + public static void openFile(Context context, File file) { + + try { + // 调用系统程序打开文件. + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setDataAndType(Uri.fromFile(file), MimeTypeMap.getSingleton() + .getMimeTypeFromExtension( + MimeTypeMap + .getFileExtensionFromUrl( + file.getPath()))); + context.startActivity(intent); + } catch (Exception ex) { + Toast.makeText(context, "打开失败.", Toast.LENGTH_SHORT).show(); + } + } + + + /** + * 根据文件路径,检查文件是否不大于指定大小 + * + * @param filepath 文件路径 + * @param maxSize 最大 + * @return 是否 + */ + public static boolean checkFileSize(String filepath, int maxSize) { + + File file = new File(filepath); + if (!file.exists() || file.isDirectory()) { + return false; + } + if (file.length() <= maxSize * 1024) { + return true; + } + else { + return false; + } + } + + + /** + * + * @param context 上下文 + * @param file 文件对象 + */ + public static void openMedia(Context context, File file) { + + if (file.getName().endsWith(".png") || + file.getName().endsWith(".jpg") || + file.getName().endsWith(".jpeg")) { + viewPhoto(context, file); + } + else { + openFile(context, file); + } + } + + + /** + * 打开多媒体文件. + * + * @param context 上下文 + * @param file 多媒体文件 + */ + public static void viewPhoto(Context context, String file) { + + viewPhoto(context, new File(file)); + } + + + /** + * 打开照片 + * @param context 上下文 + * @param file 文件对象 + */ + public static void viewPhoto(Context context, File file) { + + try { + // 调用系统程序打开文件. + Intent intent = new Intent(Intent.ACTION_VIEW); + // intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setDataAndType(Uri.fromFile(file), "image/*"); + context.startActivity(intent); + } catch (Exception ex) { + Toast.makeText(context, "打开失败.", Toast.LENGTH_SHORT).show(); + } + } + + + /** + * 将字符串以UTF-8编码保存到文件中 + * @param str 保存的字符串 + * @param fileName 文件的名字 + * @return 是否保存成功 + */ + public static boolean saveStrToFile(String str, String fileName) { + + return saveStrToFile(str, fileName, "UTF-8"); + } + + + /** + * 将字符串以charsetName编码保存到文件中 + * @param str 保存的字符串 + * @param fileName 文件的名字 + * @param charsetName 字符串编码 + * @return 是否保存成功 + */ + public static boolean saveStrToFile(String str, String fileName, String charsetName) { + + if (str == null || "".equals(str)) { + return false; + } + + FileOutputStream stream = null; + try { + File file = new File(fileName); + if (!file.getParentFile().exists()) { + file.getParentFile().mkdirs(); + } + + byte[] b = null; + if (charsetName != null && !"".equals(charsetName)) { + b = str.getBytes(charsetName); + } + else { + b = str.getBytes(); + } + + stream = new FileOutputStream(file); + stream.write(b, 0, b.length); + stream.flush(); + return true; + } catch (Exception e) { + return false; + } finally { + if (stream != null) { + try { + stream.close(); + stream = null; + } catch (Exception e) { + } + } + } + } + + + /** + * 将content://形式的uri转为实际文件路径 + * @param context 上下文 + * @param uri 地址 + * @return uri转为实际文件路径 + */ + public static String uriToPath(Context context, Uri uri) { + + Cursor cursor = null; + try { + if (uri.getScheme().equalsIgnoreCase(URI_TYPE_FILE)) { + return uri.getPath(); + } + cursor = context.getContentResolver() + .query(uri, null, null, null, null); + if (cursor.moveToFirst()) { + return cursor.getString(cursor.getColumnIndex( + MediaStore.Images.Media.DATA)); //图片文件路径 + } + } catch (Exception e) { + if (null != cursor) { + cursor.close(); + cursor = null; + } + return null; + } + return null; + } + + + /** + * 打开多媒体文件. + * + * @param context 上下文 + * @param file 多媒体文件 + */ + public static void playSound(Context context, String file) { + + playSound(context, new File(file)); + } + + + /** + * 打开多媒体文件. + * + * @param context 上下文 + * @param file 多媒体文件 + */ + public static void playSound(Context context, File file) { + + try { + // 调用系统程序打开文件. + Intent intent = new Intent(Intent.ACTION_VIEW); + // intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + // intent.setClassName("com.android.music", "com.android.music.MediaPlaybackActivity"); + intent.setDataAndType(Uri.fromFile(file), "audio/*"); + context.startActivity(intent); + } catch (Exception ex) { + Toast.makeText(context, "打开失败.", Toast.LENGTH_SHORT).show(); + } + } + + + /** + * 打开视频文件. + * + * @param context 上下文 + * @param file 视频文件 + */ + public static void playVideo(Context context, String file) { + + playVideo(context, new File(file)); + } + + + /** + * 打开视频文件. + * @param context 上下文 + * @param file 视频文件 + */ + public static void playVideo(Context context, File file) { + try { + // 调用系统程序打开文件. + Intent intent = new Intent(Intent.ACTION_VIEW); + // intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setDataAndType(Uri.fromFile(file), "video/*"); + context.startActivity(intent); + } catch (Exception ex) { + Toast.makeText(context, "打开失败.", Toast.LENGTH_SHORT).show(); + } + } + + + /** + * 文件重命名 + * + * @param oldPath 旧的文件名字 + * @param newPath 新的文件名字 + */ + public static void renameFile(String oldPath, String newPath) { + + try { + if (!TextUtils.isEmpty(oldPath) && !TextUtils.isEmpty(newPath) + && !oldPath.equals(newPath)) { + File fileOld = new File(oldPath); + File fileNew = new File(newPath); + fileOld.renameTo(fileNew); + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/outdoor/util/IOUtils.java b/app/src/main/java/com/navinfo/outdoor/util/IOUtils.java new file mode 100644 index 0000000..a1f99f1 --- /dev/null +++ b/app/src/main/java/com/navinfo/outdoor/util/IOUtils.java @@ -0,0 +1,98 @@ +package com.navinfo.outdoor.util; + +import java.io.Closeable; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +/** + * IO utils + * + * @author Vladislav Bauer + */ + +public class IOUtils { + + private IOUtils() { + throw new AssertionError(); + } + + + /** + * Close closable object and wrap {@link IOException} with {@link + * RuntimeException} + * + * @param closeable closeable object + */ + public static void close(Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (IOException e) { + throw new RuntimeException("IOException occurred. ", e); + } + } + } + + + /** + * Close closable and hide possible {@link IOException} + * + * @param closeable closeable object + */ + public static void closeQuietly(Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (IOException e) { + // Ignored + } + } + } + + + /** + *保存文本 + * @param fileName 文件名字 + * @param content 内容 + * @param append 是否累加 + * @return 是否成功 + */ + public static boolean saveTextValue(String fileName, String content, boolean append) { + + try { + File textFile = new File(fileName); + if (!append && textFile.exists()) textFile.delete(); + + FileOutputStream os = new FileOutputStream(textFile); + os.write(content.getBytes("UTF-8")); + os.close(); + } catch (Exception ee) { + return false; + } + + return true; + } + + + /** + * 删除目录下所有文件 + * @param Path 路径 + */ + public static void deleteAllFile(String Path) { + + // 删除目录下所有文件 + File path = new File(Path); + File files[] = path.listFiles(); + if (files != null) { + for (File tfi : files) { + if (tfi.isDirectory()) { + System.out.println(tfi.getName()); + } + else { + tfi.delete(); + } + } + } + } +} diff --git a/app/src/main/java/com/navinfo/outdoor/util/StringUtils.java b/app/src/main/java/com/navinfo/outdoor/util/StringUtils.java new file mode 100644 index 0000000..3c10205 --- /dev/null +++ b/app/src/main/java/com/navinfo/outdoor/util/StringUtils.java @@ -0,0 +1,703 @@ +package com.navinfo.outdoor.util; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + *

字符串工具类,提供一些字符串相关的便捷方法

+ */ +public class StringUtils { + + private StringUtils() { + throw new AssertionError(); + } + + + /** + * is null or its length is 0 or it is made by space + * + *
+     * isBlank(null) = true;
+     * isBlank("") = true;
+     * isBlank("  ") = true;
+     * isBlank("a") = false;
+     * isBlank("a ") = false;
+     * isBlank(" a") = false;
+     * isBlank("a b") = false;
+     * 
+ * + * @param str str + * @return if string is null or its size is 0 or it is made by space, return + * true, else return false. + */ + public static boolean isBlank(String str) { + + return (str == null || str.trim().length() == 0); + } + + + /** + * is null or its length is 0 + * + *
+     * isEmpty(null) = true;
+     * isEmpty("") = true;
+     * isEmpty("  ") = false;
+     * 
+ * + * @param str str + * @return if string is null or its size is 0, return true, else return + * false. + */ + public static boolean isEmpty(CharSequence str) { + + return (str == null || str.length() == 0); + } + + + /** + * get length of CharSequence + * + *
+     * length(null) = 0;
+     * length(\"\") = 0;
+     * length(\"abc\") = 3;
+     * 
+ * + * @param str str + * @return if str is null or empty, return 0, else return {@link + * CharSequence#length()}. + */ + public static int length(CharSequence str) { + + return str == null ? 0 : str.length(); + } + + + /** + * null Object to empty string + * + *
+     * nullStrToEmpty(null) = "";
+     * nullStrToEmpty("") = "";
+     * nullStrToEmpty("aa") = "aa";
+     * 
+ * + * @param str str + * @return String + */ + public static String nullStrToEmpty(Object str) { + + return (str == null + ? "" + : (str instanceof String ? (String) str : str.toString())); + } + + + /** + * @param str str + * @return String + */ + public static String capitalizeFirstLetter(String str) { + + if (isEmpty(str)) { + return str; + } + + char c = str.charAt(0); + return (!Character.isLetter(c) || Character.isUpperCase(c)) + ? str + : new StringBuilder(str.length()).append( + Character.toUpperCase(c)) + .append(str.substring(1)) + .toString(); + } + + + /** + * encoded in utf-8 + * + * @param str 字符串 + * @return 返回一个utf8的字符串 + */ + public static String utf8Encode(String str) { + + if (!isEmpty(str) && str.getBytes().length != str.length()) { + try { + return URLEncoder.encode(str, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException( + "UnsupportedEncodingException occurred. ", e); + } + } + return str; + } + + + /** + * @param href 字符串 + * @return 返回一个html + */ + public static String getHrefInnerHtml(String href) { + + if (isEmpty(href)) { + return ""; + } + + String hrefReg = ".*<[\\s]*a[\\s]*.*>(.+?)<[\\s]*/a[\\s]*>.*"; + Pattern hrefPattern = Pattern.compile(hrefReg, + Pattern.CASE_INSENSITIVE); + Matcher hrefMatcher = hrefPattern.matcher(href); + if (hrefMatcher.matches()) { + return hrefMatcher.group(1); + } + return href; + } + + + /** + * @param source 字符串 + * @return 返回htmL到字符串 + */ + public static String htmlEscapeCharsToString(String source) { + + return StringUtils.isEmpty(source) + ? source + : source.replaceAll("<", "<") + .replaceAll(">", ">") + .replaceAll("&", "&") + .replaceAll(""", "\""); + } + + + /** + * @param s str + * @return String + */ + public static String fullWidthToHalfWidth(String s) { + + if (isEmpty(s)) { + return s; + } + + char[] source = s.toCharArray(); + for (int i = 0; i < source.length; i++) { + if (source[i] == 12288) { + source[i] = ' '; + // } else if (source[i] == 12290) { + // source[i] = '.'; + } + else if (source[i] >= 65281 && source[i] <= 65374) { + source[i] = (char) (source[i] - 65248); + } + else { + source[i] = source[i]; + } + } + return new String(source); + } + + + /** + * @param s 字符串 + * @return 返回的数值 + */ + public static String halfWidthToFullWidth(String s) { + + if (isEmpty(s)) { + return s; + } + + char[] source = s.toCharArray(); + for (int i = 0; i < source.length; i++) { + if (source[i] == ' ') { + source[i] = (char) 12288; + // } else if (source[i] == '.') { + // source[i] = (char)12290; + } + else if (source[i] >= 33 && source[i] <= 126) { + source[i] = (char) (source[i] + 65248); + } + else { + source[i] = source[i]; + } + } + return new String(source); + } + + + /** + * @param str 资源 + * @return 特殊字符串切换 + */ + + public static String replaceBlanktihuan(String str) { + + String dest = ""; + if (str != null) { + Pattern p = Pattern.compile("\\s*|\t|\r|\n"); + Matcher m = p.matcher(str); + dest = m.replaceAll(""); + } + return dest; + } + + + /** + * 判断给定的字符串是否为null或者是空的 + * + * @param string 给定的字符串 + */ + public static boolean isEmpty(String string) { + return string == null || "".equals(string.trim()); + } + + + /** + * 判断给定的字符串是否不为null且不为空 + * + * @param string 给定的字符串 + */ + public static boolean isNotEmpty(String string) { + return !isEmpty(string); + } + + + /** + * 判断给定的字符串数组中的所有字符串是否都为null或者是空的 + * + * @param strings 给定的字符串 + */ + public static boolean isEmpty(String... strings) { + boolean result = true; + for (String string : strings) { + if (isNotEmpty(string)) { + result = false; + break; + } + } + return result; + } + + + /** + * 判断给定的字符串数组中是否全部都不为null且不为空 + * + * @param strings 给定的字符串数组 + * @return 是否全部都不为null且不为空 + */ + public static boolean isNotEmpty(String... strings) { + boolean result = true; + for (String string : strings) { + if (isEmpty(string)) { + result = false; + break; + } + } + return result; + } + + + /** + * 如果字符串是null或者空就返回"" + */ + public static String filterEmpty(String string) { + return StringUtils.isNotEmpty(string) ? string : ""; + } + + + /** + * 在给定的字符串中,用新的字符替换所有旧的字符 + * + * @param string 给定的字符串 + * @param oldchar 旧的字符 + * @param newchar 新的字符 + * @return 替换后的字符串 + */ + public static String replace(String string, char oldchar, char newchar) { + char chars[] = string.toCharArray(); + for (int w = 0; w < chars.length; w++) { + if (chars[w] == oldchar) { + chars[w] = newchar; + break; + } + } + return new String(chars); + } + + + /** + * 把给定的字符串用给定的字符分割 + * + * @param string 给定的字符串 + * @param ch 给定的字符 + * @return 分割后的字符串数组 + */ + public static String[] split(String string, char ch) { + ArrayList stringList = new ArrayList(); + char chars[] = string.toCharArray(); + int nextStart = 0; + for (int w = 0; w < chars.length; w++) { + if (ch == chars[w]) { + stringList.add(new String(chars, nextStart, w - nextStart)); + nextStart = w + 1; + if (nextStart == + chars.length) { //当最后一位是分割符的话,就再添加一个空的字符串到分割数组中去 + stringList.add(""); + } + } + } + if (nextStart < + chars.length) { //如果最后一位不是分隔符的话,就将最后一个分割符到最后一个字符中间的左右字符串作为一个字符串添加到分割数组中去 + stringList.add(new String(chars, nextStart, + chars.length - 1 - nextStart + 1)); + } + return stringList.toArray(new String[stringList.size()]); + } + + + /** + * 计算给定的字符串的长度,计算规则是:一个汉字的长度为2,一个字符的长度为1 + * + * @param string 给定的字符串 + * @return 长度 + */ + public static int countLength(String string) { + int length = 0; + char[] chars = string.toCharArray(); + for (int w = 0; w < string.length(); w++) { + char ch = chars[w]; + if (ch >= '\u0391' && ch <= '\uFFE5') { + length++; + length++; + } + else { + length++; + } + } + return length; + } + + + private static char[] getChars(char[] chars, int startIndex) { + int endIndex = startIndex + 1; + //如果第一个是数字 + if (Character.isDigit(chars[startIndex])) { + //如果下一个是数字 + while (endIndex < chars.length && + Character.isDigit(chars[endIndex])) { + endIndex++; + } + } + char[] resultChars = new char[endIndex - startIndex]; + System.arraycopy(chars, startIndex, resultChars, 0, resultChars.length); + return resultChars; + } + + + /** + * 是否全是数字 + */ + public static boolean isAllDigital(char[] chars) { + boolean result = true; + for (int w = 0; w < chars.length; w++) { + if (!Character.isDigit(chars[w])) { + result = false; + break; + } + } + return result; + } + + + + + /** + * 删除给定字符串中所有的旧的字符 + * + * @param string 源字符串 + * @param ch 要删除的字符 + * @return 删除后的字符串 + */ + public static String removeChar(String string, char ch) { + StringBuffer sb = new StringBuffer(); + for (char cha : string.toCharArray()) { + if (cha != '-') { + sb.append(cha); + } + } + return sb.toString(); + } + + + /** + * 删除给定字符串中给定位置处的字符 + * + * @param string 给定字符串 + * @param index 给定位置 + */ + public static String removeChar(String string, int index) { + String result = null; + char[] chars = string.toCharArray(); + if (index == 0) { + result = new String(chars, 1, chars.length - 1); + } + else if (index == chars.length - 1) { + result = new String(chars, 0, chars.length - 1); + } + else { + result = new String(chars, 0, index) + + new String(chars, index + 1, chars.length - index); + ; + } + return result; + } + + + /** + * 删除给定字符串中给定位置处的字符 + * + * @param string 给定字符串 + * @param index 给定位置 + * @param ch 如果同给定位置处的字符相同,则将给定位置处的字符删除 + */ + public static String removeChar(String string, int index, char ch) { + String result = null; + char[] chars = string.toCharArray(); + if (chars.length > 0 && chars[index] == ch) { + if (index == 0) { + result = new String(chars, 1, chars.length - 1); + } + else if (index == chars.length - 1) { + result = new String(chars, 0, chars.length - 1); + } + else { + result = new String(chars, 0, index) + + new String(chars, index + 1, chars.length - index); + ; + } + } + else { + result = string; + } + return result; + } + + + /** + * 对给定的字符串进行空白过滤 + * + * @param string 给定的字符串 + * @return 如果给定的字符串是一个空白字符串,那么返回null;否则返回本身。 + */ + public static String filterBlank(String string) { + if ("".equals(string)) { + return null; + } + else { + return string; + } + } + + + /** + * 将给定字符串中给定的区域的字符转换成小写 + * + * @param str 给定字符串中 + * @param beginIndex 开始索引(包括) + * @param endIndex 结束索引(不包括) + * @return 新的字符串 + */ + public static String toLowerCase(String str, int beginIndex, int endIndex) { + return str.replaceFirst(str.substring(beginIndex, endIndex), + str.substring(beginIndex, endIndex) + .toLowerCase(Locale.getDefault())); + } + + + /** + * 将给定字符串中给定的区域的字符转换成大写 + * + * @param str 给定字符串中 + * @param beginIndex 开始索引(包括) + * @param endIndex 结束索引(不包括) + * @return 新的字符串 + */ + public static String toUpperCase(String str, int beginIndex, int endIndex) { + return str.replaceFirst(str.substring(beginIndex, endIndex), + str.substring(beginIndex, endIndex) + .toUpperCase(Locale.getDefault())); + } + + + /** + * 将给定字符串的首字母转为小写 + * + * @param str 给定字符串 + * @return 新的字符串 + */ + public static String firstLetterToLowerCase(String str) { + return toLowerCase(str, 0, 1); + } + + + /** + * 将给定字符串的首字母转为大写 + * + * @param str 给定字符串 + * @return 新的字符串 + */ + public static String firstLetterToUpperCase(String str) { + return toUpperCase(str, 0, 1); + } + + + /** + * 将给定的字符串MD5加密 + * + * @param string 给定的字符串 + * @return MD5加密后生成的字符串 + */ + public static String MD5(String string) { + String result = null; + try { + char[] charArray = string.toCharArray(); + byte[] byteArray = new byte[charArray.length]; + for (int i = 0; i < charArray.length; i++) { + byteArray[i] = (byte) charArray[i]; + } + + StringBuffer hexValue = new StringBuffer(); + byte[] md5Bytes = MessageDigest.getInstance("MD5") + .digest(byteArray); + for (int i = 0; i < md5Bytes.length; i++) { + int val = ((int) md5Bytes[i]) & 0xff; + if (val < 16) { + hexValue.append("0"); + } + hexValue.append(Integer.toHexString(val)); + } + + result = hexValue.toString(); + } catch (Exception e) { + e.printStackTrace(); + } + return result; + } + + + /** + * 判断给定的字符串是否以一个特定的字符串开头,忽略大小写 + * + * @param sourceString 给定的字符串 + * @param newString 一个特定的字符串 + */ + public static boolean startsWithIgnoreCase(String sourceString, String newString) { + int newLength = newString.length(); + int sourceLength = sourceString.length(); + if (newLength == sourceLength) { + return newString.equalsIgnoreCase(sourceString); + } + else if (newLength < sourceLength) { + char[] newChars = new char[newLength]; + sourceString.getChars(0, newLength, newChars, 0); + return newString.equalsIgnoreCase(String.valueOf(newChars)); + } + else { + return false; + } + } + + + /** + * 判断给定的字符串是否以一个特定的字符串结尾,忽略大小写 + * + * @param sourceString 给定的字符串 + * @param newString 一个特定的字符串 + */ + public static boolean endsWithIgnoreCase(String sourceString, String newString) { + int newLength = newString.length(); + int sourceLength = sourceString.length(); + if (newLength == sourceLength) { + return newString.equalsIgnoreCase(sourceString); + } + else if (newLength < sourceLength) { + char[] newChars = new char[newLength]; + sourceString.getChars(sourceLength - newLength, sourceLength, + newChars, 0); + return newString.equalsIgnoreCase(String.valueOf(newChars)); + } + else { + return false; + } + } + + + /** + * 检查字符串长度,如果字符串的长度超过maxLength,就截取前maxLength个字符串并在末尾拼上appendString + */ + public static String checkLength(String string, int maxLength, String appendString) { + if (string.length() > maxLength) { + string = string.substring(0, maxLength); + if (appendString != null) { + string += appendString; + } + } + return string; + } + + + /** + * 检查字符串长度,如果字符串的长度超过maxLength,就截取前maxLength个字符串并在末尾拼上… + */ + public static String checkLength(String string, int maxLength) { + return checkLength(string, maxLength, "…"); + } + + + /** + * 删除Html标签 + * + * @param inputString + * @return + */ + public static String htmlRemoveTag(String inputString) { + if (inputString == null) + return null; + String htmlStr = inputString; // 含html标签的字符串 + String textStr = ""; + java.util.regex.Pattern p_script; + java.util.regex.Matcher m_script; + java.util.regex.Pattern p_style; + java.util.regex.Matcher m_style; + java.util.regex.Pattern p_html; + java.util.regex.Matcher m_html; + try { + //定义script的正则表达式{或]*?>[\\s\\S]*?<\\/script> + String regEx_script = "<[\\s]*?script[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?script[\\s]*?>"; + //定义style的正则表达式{或]*?>[\\s\\S]*?<\\/style> + String regEx_style = "<[\\s]*?style[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?style[\\s]*?>"; + String regEx_html = "<[^>]+>"; // 定义HTML标签的正则表达式 + p_script = Pattern.compile(regEx_script, Pattern.CASE_INSENSITIVE); + m_script = p_script.matcher(htmlStr); + htmlStr = m_script.replaceAll(""); // 过滤script标签 + p_style = Pattern.compile(regEx_style, Pattern.CASE_INSENSITIVE); + m_style = p_style.matcher(htmlStr); + htmlStr = m_style.replaceAll(""); // 过滤style标签 + p_html = Pattern.compile(regEx_html, Pattern.CASE_INSENSITIVE); + m_html = p_html.matcher(htmlStr); + htmlStr = m_html.replaceAll(""); // 过滤html标签 + textStr = htmlStr; + } catch (Exception e) { + e.printStackTrace(); + } + return textStr;// 返回文本字符串 + } + + +} diff --git a/app/src/main/res/layout/activity_picture.xml b/app/src/main/res/layout/activity_picture.xml index 1b536cc..c0994f9 100644 --- a/app/src/main/res/layout/activity_picture.xml +++ b/app/src/main/res/layout/activity_picture.xml @@ -55,7 +55,7 @@ app:layout_constraintTop_toTopOf="parent" /> -